3.1搜索而不是拍照上传
鱼书网站是赠书的平台,所以不需要提供书的用户拍照和填写相关信息上传到平台。
3.2 数据API
数据不是来源于数据库,来源于API
1、教程提供
2、豆瓣网(格式略有不同)
3.3搜索关键字
@app.route('/book/search/')
def search(q,page):
# q:普通关键字 isbn
# page
# isbn isbn13 13个0到9的数字组成
# isbn10 10个0到9数字组成,含有一些‘_’
isbn_or_key = 'key'
if len(q) == 13 and q.isdigit():
isbn_or_key = 'isbn'
short_q = q.replace('_','')
if '_' in q and len(short_q) == 10 and short_q.isdigit:
isbn_or_key = 'isbn'
pass
3.4简单的重构
所有的代码都到视图里是不合理的,我们新建一个helper.py,将isbn的函数移过去,这样函数代码就被封装起来
# isbn isbn13 13个0到9的数字组成
# isbn10 10个0到9数字组成,含有一些‘_’
def is_isbn_or_key(word):
isbn_or_key = 'key'
if len(word) == 13 and q.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 helper import is_isbn_or_key
引用这个判断函数
def search(q,page):
# q:普通关键字 isbn
# page
isbn_or_key = is_isbn_or_key(q)
pass
3.5 requests发送http请求及代码的简化手段
新建HTTP.py
class HTTP:
def get(self):
pass
使用repuests,先在命令行安装
(注,图片中pipenv 误输入成了pinenv)
# urllib
# requests
from urllib import request
import requests
# http://t.yushu.im/v2/book/isbn/9787501524044
class HTTP:
def get(self,url,return_json=True):
r = requests.get(url)
# restful
# json
if r.status_code !=200:
return {} if return_json else ''
return r.json() if return_json else r.text
# if r.status_code == 200:
# if return_json:
# return r.json()
# else:
# return r.text
# else:
# if return_json:
# return {}
# else:
1.简化if-else语句的几种方式 1.使用三元表达式 ;2.if+return;3.将if-else里的代码提取成函数
2.if+return的理解:把最后一句return前的if+return 全都理解为正常流程之外的一种特例情况的处理;多次if-return,提前结束一些逻辑分支,可以提高代码思维的清晰性
3.requests的一些说明:1.get()发送get请求;2.返回结果r.status_code 获取返回状态吗;3.r.json()将返回结果序列化成json;4.r.text 将返回结果不做处理直接返回
3.6 requests vs urllib
发送http请求的两种方法:
1.使用urllib(python内置)
2.使用requests(需要使用pip3安装)
import requests
# http://t.yushu.im/v2/book/isbn/9787501524044
class HTTP:
@staticmethod
def get(url, return_json=True):
r = requests.get(url)
# restful
# json
if r.status_code != 200:
return {} if return_json else ''
return r.json() if return_json else r.text
3.7 从API获取数据
新建一个文件:yushu_book.py
定义一个类,定义两个方法
from http import HTTP
class YuShuBook:
isbn_url = 'http://t.yushu.im/v2/book/isbn/{}'
keyword_url = 'http://t.yushu.im/v2/book/search?q={}&count={}&start={}'
@classmethod
def search_by_isbn(cls,isbn):
url = cls.isbn_url.format(isbn)
result = HTTP.get(url)
# dict
return result
@classmethod
def search_by_keyword(cls, keyword, count=15,start=0):
url = cls.keyword_url.format(keyword,count,start)
result = HTTP.get(url)
return result
3.8 使用jsonify
fisher.py中,jsonnify的用法
@app.route('/book/search/')
def search(q, page):
# q:普通关键字 isbn
# page
# alt + enter ,将光标放在YuShuBook上,按alt + enter,
# 然后选择YuShuBook所在yushu_book.py,会自动在本文件中from yushu_book import YuShuBook
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)
# dict 序列化
# API
return jsonify(result)
# return json.dumps(result),200,{'content-type':'application/json'}
3.9 将视图函数拆分到单独的文件中
不能将所有的视图函数都放到一个文件中,比较好的做法是根据业务模块来分。
入口文件fisher.py还是放到根目录下面,我们在根目录下建立一个子目录app,在app下面新建一个目录web,将视图函数分门别类的存放到web目录下面。
首先在 web目录下新建一个文件book.py,将fisher.py中的视图函数移到book.py中,在book.py中导入相关引用文件。
3.10 深入了解flask路由
flask的基本思想是内部会维护一个字典。每一个url都会对应一个视图函数,但是不仅仅是这样。每一个url还会对应一个endpoint端点。用于反向构建URL(后面会讲解)
flask的路由注册app_url_rule(url=,view_func=,endpoint=)会接受三个参数,前两个我们都知道了,第三个就是上面说的endpoint。他的默认值是view_func的名称。当然,app.route('url',endpoint=)也可以传入
3.11 循环引入流程分析
fisher.py和book.py出现了循环引入的情况。下面看下fisher.py和book.py的具体流程图
图中有两种颜色的线:红色的线是fisher主执行文件被执行之后的执行路径;蓝色的线是book模块被导入之后循环导入的执行路径。
1.主流程开始之后,首先到达导入book的语句。然后进入book模块中执行
2.book模块开始之后,首先到达导入fisher的语句(循环导入),这个时候主流程暂时结束,重新执行fisher中的代码
3.这时候又回到fisher中的导入book的语句,由于book已经被导入一次,所以不会再次导入,进入if语句,这个时候的name是book导入fisher时候的name:fisher,不是主流程main,所以if语句条件为false。蓝色线执行终止,重新回到2. book导入fisher的语句。
4.继续向下执行book 中app.route注册路由的语句。然后book执行完,回到fisher主流程执行中。
5.到达if语句,这个时候name为main。执行run方法,启动服务
回答流程图中的两个问题:
问题1:因为都是由fisher引入book,一个模块只会引入另一个模块一次。所以只执行了一次book
问题2:由于一次是主流程执行fisher文件;一次是由book模块导入 fisher。
3.12 找不到视图函数的最终解释与证明
整个流程中,出现了两次核心app对象的初始化,注册路由是在蓝色流程中初始化的app注册的。但是启动服务是红色流程中的app启动的
book中注册路由所使用的app对象,是他自己所导入fisher模块的app对象(蓝色流程中),而不是红色主流程中所实例化的app对象