2.資料與flask路由
阿新 • • 發佈:2019-02-20
一. 書籍搜尋與查詢
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)
# 這裡result是dict, 我們要轉為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)
# 這裡result是dict, 我們要轉為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不是同一個例項物件, 這是執行出錯的根源。這種錯誤稱為迴圈引用: