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)
# 这里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视图函数已经添加成功, 所以这里不是运行错误的原因。
六. 循环引用
我们修改book.py和fisher.py, 打印各自app的内存地址
book.py
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不是同一个实例对象, 这是运行出错的根源。这种错误称为循环引用:
上一篇: 高品质低价格 脉宝云店以实力著称
下一篇: PostgreSQL中的替代变量实现