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

修改fisher.py

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获取数据

新建httper.py:

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

修改fisher.py:

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)

并在fisher.py中尝试导入book.py:

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)

fisher.py

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不是同一个实例对象, 这是运行出错的根源。这种错误称为循环引用:


猜你喜欢

转载自blog.csdn.net/weixin_41207499/article/details/80706902