1. 程式人生 > >2.資料與flask路由

2.資料與flask路由

一. 書籍搜尋與查詢

1. 資料API

關鍵字搜尋

http://t.yushu.im/v2/book/search?q={}&start={}&count={}

isbn搜尋

http://t.yushu.im/v2/book/isbn/{isbn}

豆瓣API

http://api.douban.com/v2/book

2. 搜尋關鍵字

實現搜尋書籍的檢視函式search ,修改fisher.py

from flask import Flask


app = Flask(__name__)
app.config.from_object('config')  # 傳入模組的路徑


@app.route('/book/search/<q>/<page>')   # <>表示傳入引數
def search(q, page): """[summary] Arguments: q {[str]} -- [普通關鍵字] page {[int]} """ isbn_or_key = 'key' if len(q) == 13 and q.isdigit(): # 判斷是否是isbn號碼 isbn_or_key = 'isbn' short_q = q.replace('-', '') # and的先後順序有影響, 越有可能是假的就放前面, 消耗資源的如查詢資料庫放後面
if '-' in q and len(short_q) == 10 and short_q.isdigit(): isbn_or_key = 'isbn' pass if __name__ == '__main__': app.run(host='0.0.0.0', debug=app.config['DEBUG'], port=81)

3. 對程式碼優化

檢視函式儘量不要把所有程式碼都放入,把檢視函式變得很臃腫。
我們將fisher.py為例子,進行優化:
編寫helper.py,把判斷搜尋書籍的是關鍵字還是isbn碼的邏輯抽離:

def is_isbn_or_key
(word):
""" 判斷傳入引數是 關鍵字搜尋還是isbn編號 :param word: :return: isbn_or_key """ isbn_or_key = 'key' if len(word) == 13 and word.isdigit(): isbn_or_key = 'isbn' short_word = word.replace('-', '') if '-' in word and len(short_word) == 10 and short_word.isdigit(): isbn_or_key = 'isbn' return isbn_or_key
from flask import Flask
from helper import is_isbn_or_key    # helper.py匯入

app = Flask(__name__)
app.config.from_object('config')  # 傳入模組的路徑


@app.route('/book/search/<q>/<page>')
def search(q, page):
    """

    :param q:
    :param page:
    :return:
    """
    isbn_or_key = is_isbn_or_key(q)    # 簡化了search檢視函式的程式碼,方便閱讀
    pass


if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=app.config['DEBUG'], port=81)

二. 獲取書籍資料:從api獲取資料

import requests


class HTTP: # 使用類 方便以後拓展
    @staticmethod
    def get(url, returned_json=True):


        """

        :param url:
        :param returned_json:
        :return:
        """
        r = requests.get(url)

        # 未簡化版
        # if r.status_code == 200:
        #     if returned_json:
        #         return r.json()    # 返回json格式
        #     else:
        #         return r.text    # 返回原始字串
        # else:
        #     if returned_json:
        #         return {}
        #     else:
        #         return ""

        # 簡化程式碼,儘量減少return語句
        if r.status_code != 200:     # 根據狀態碼判斷是否返回成功
            return {} if returned_json else ''
        return r.json() if returned_json else r.text
from flask import Flask
from helper import is_isbn_or_key
from yushu_book import YuShuBook
import json

app = Flask(__name__)
app.config.from_object('config')  # 傳入模組的路徑


@app.route('/book/search/<q>/<page>')
def search(q, page):
    """

    :param q:
    :param page:
    :return:
    """
    isbn_or_key = is_isbn_or_key(q)
    if isbn_or_key == 'isbn':
        result = YuShuBook.search_by_isbn(q)
    else:
        result = YuShuBook.search_by_keyword(q)

        # 這裡resultdict 我們要轉為json
    return json.dumps(result), 200, {'content-type': 'application/json'}   # 設定瀏覽器顯示方式為json



if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=app.config['DEBUG'], port=81)

執行程式, 得到結果:



三. 使用jsonify

fisher.py的search檢視函式最後返回時使用了json.dump,200狀態碼, 以及json對應的content-type, 我們可以用flask的jsonify簡化:
修改fisher.py:

from flask import Flask, jsonify
from helper import is_isbn_or_key
from yushu_book import YuShuBook
import json

app = Flask(__name__)
app.config.from_object('config')  # 傳入模組的路徑


@app.route('/book/search/<q>/<page>')
def search(q, page):
    """

    :param q:
    :param page:
    :return:
    """
    isbn_or_key = is_isbn_or_key(q)
    if isbn_or_key == 'isbn':
        result = YuShuBook.search_by_isbn(q)
    else:
        result = YuShuBook.search_by_keyword(q)

        # 這裡resultdict 我們要轉為json
    # return json.dumps(result), 200, {'content-type': 'application/json'}   # 設定瀏覽器顯示方式為json
    return jsonify(result)   # jsonify簡化



if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=app.config['DEBUG'], port=81)

四. 將檢視函式拆分到單獨的檔案中

我們在專案的根目錄下新建/app/web/book.py, 然後將檢視函式search單獨放在book.py中:

from helper import is_isbn_or_key
from yushu_book import YuShuBook
from flask import jsonify
from fisher import app   # 匯入app



@app.route('/book/search/<q>/<page>')
def search(q, page):
    """

    :param q:
    :param page:
    :return:
    """
    isbn_or_key = is_isbn_or_key(q)
    if isbn_or_key == 'isbn':
        result = YuShuBook.search_by_isbn(q)
    else:
        result = YuShuBook.search_by_keyword(q)

    return jsonify(result)
from flask import Flask, jsonify

app = Flask(__name__)
app.config.from_object('config')  # 傳入模組的路徑

from app.web import book   # 匯入檢視函式

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=app.config['DEBUG'], port=81)

但是執行後發現會報錯, 是什麼原因?

五. 深入瞭解flask路由

flask的路由註冊成功需要兩個條件, 我們進入app.route的原始碼內部, 看到:

 def decorator(f):
            endpoint = options.pop('endpoint', None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator

app.route內部其實也是呼叫了add_url_rule, 我們進入add_url_rule檢視:

 if view_func is not None:
            old_func = self.view_functions.get(endpoint)
            if old_func is not None and old_func != view_func:
                raise AssertionError('View function mapping is overwriting an '
                                     'existing endpoint function: %s' % endpoint)
            self.view_functions[endpoint] = view_func

self.view_functions[endpoint] = view_func這句程式碼中可以看出,view_functions這個字典會以endpoint為key,view_func為value存放檢視函式。但通過除錯模式, 我們發現search檢視函式已經新增成功, 所以這裡不是執行錯誤的原因。

六. 迴圈引用

from helper import is_isbn_or_key
from yushu_book import YuShuBook
from flask import jsonify
from fisher import app

print('book app', id(app))
@app.route('/book/search/<q>/<page>')
def search(q, page):
    """

    :param q:
    :param page:
    :return:
    """
    isbn_or_key = is_isbn_or_key(q)
    if isbn_or_key == 'isbn':
        result = YuShuBook.search_by_isbn(q)
    else:
        result = YuShuBook.search_by_keyword(q)

    return jsonify(result)

from flask import Flask, jsonify

app = Flask(__name__)
app.config.from_object('config')  # 傳入模組的路徑
print('app1', id(app))

from app.web import book

if __name__ == '__main__':
    print('app.run', id(app))
    app.run(host='0.0.0.0', debug=app.config['DEBUG'], port=81)

執行得到列印結果:

app1 4355270808
app1 4375092304
book app 4375092304
app.run 4355270808

可以看出book.py中app與fisher.py中app不是同一個例項物件, 這是執行出錯的根源。這種錯誤稱為迴圈引用: