I、路由参数
1、匹配串类型
路由参数可以进行定制类型,我们的语法格式如下:
@app.route('/user/<int:user_id>')
启动后我们匹配路由串user/aaa和user/111,观察结果
2、请求方式
除了我们可以指定路由匹配参数的属性(默认为string类型,可指定如整型参数等)。我们还可以指定在该路由下的请求方式(GET、POST),方式如下例子:
@app.route('/demo2', methods=['GET', 'POST'])
def demo2():
return request.method
我们启动服务后,利用postman进行测试。
II、传输数据
1、json:通用数据格式
首先我们先在pycharm中建立一个json文件test.json
{
"subjects": [
{
"rate": "7.5",
"cover_x": 4429,
"name": "传闻中的陈芊芊",
"url": "https://movie.douban.com/subject/34463197/",
"playable": true,
"cover": "https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2602398693.webp"
},
{
"rate": "7.5",
"cover_x": 4429,
"name": "传闻中的陈芊芊",
"url": "https://movie.douban.com/subject/34463197/",
"playable": true,
"cover": "https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2602398693.webp"
},
{
"rate": "7.5",
"cover_x": 4429,
"name": "传闻中的陈芊芊",
"url": "https://movie.douban.com/subject/34463197/",
"playable": true,
"cover": "https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2602398693.webp"
}
]
}
我们来观察一下json的格式,它有点像python的字典的{"key":"value"}
,其中json内存在对象和数组,比较容易看出用 { }
括的为对象,用 [ ]
括的为数组。因此json可以看成{"key":["key":"value"]}
的一种数据格式。
**2、案例
接下来我们创建一个json传输案例来体验一下这种数据传输方式
首先在原有的flask项目内创建json_demo.py文件,编辑文件
# 创建一个json字符串
tvs = """{
"subjects": [
{
"rate": "7.5",
"cover_x": 4429,
"name": "传闻中的陈芊芊",
"url": "https://movie.douban.com/subject/34463197/",
"playable": true,
"cover": "https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2602398693.webp"
},
{
"rate": "7.5",
"cover_x": 4429,
"name": "传闻中的陈芊芊",
"url": "https://movie.douban.com/subject/34463197/",
"playable": true,
"cover": "https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2602398693.webp"
},
{
"rate": "7.5",
"cover_x": 4429,
"name": "传闻中的陈芊芊",
"url": "https://movie.douban.com/subject/34463197/",
"playable": true,
"cover": "https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2602398693.webp"
}
]
}"""
import json
# json.loads()将json字符串转化为字典
print(type(tvs))
tvs_dict = json.loads(tvs)
print(type(tvs_dict))
print([x for x in tvs_dict["subjects"][:2]])
运行观察结果
继而我们看如何将python的字典类型转化为json数据格式
json_dict = {"name": "kick", "age": 18}
res = json.dumps(json_dict)
print(type(res))
3、一个传输json的案例
我们在app.py内编写如下代码:
from flask import jsonify
@app.route('/demo3')
def demo3():
json_dict = {"name": "kick", "age": 10}
return jsonify(json_dict)
那么观察两段案例,我们使用
json.dumps()
也可以使得字典返回json格式,那么我们用jsonify()
是否和json.dumps()
一样可以通用呢?
其实不然,我们不推荐使用json.dumps()
因为返回数据要符合HTTP协议的规范要求
为了体会这种区别,我们再在app.py内编写一段demo4
@app.route('/demo4')
def demo4():
json_dict = {"name": "kick", "age": 18}
return json.dumps(json_dict)
我们打开浏览器,检查Network的XHR,观察两段案例的返回值格式
由此我们不难看出差别。
III、重定向
1、外部重定向
我们先制定一段demo5
from flask import redirect
@app.route('/demo5')
def demo5():
return redirect("http://www.baidu.com")
打开浏览器进入 http://127.0.0.1:5000/demo5即可重定向入百度
2、内部重定向
为了更加了解redirect我们再书写一段demo6
from flask import url_for
@app.route('/demo6')
def demo6():
return redirect(url_for('demo3'))
url_for()
类似于Django模板中使用的{% url ' ' %}
是用于定向自身路由的函数,利用url_for()
即可重定向或定向自身路由进行跳转。
3、重定向到带参数的视图函数
接下来我们看如何重定向到带参数的视图函数
# 先前编写过得带参数的视图函数
@app.route('/user/<int:user_id>')
def user_info(user_id):
return 'hello{}'.format(user_id)
# 带参数的重定向
@app.route('/demo7')
def demo7():
return redirect(url_for('user_info', user_id=1000))
我们只需要url_for('url', 参数名=value)
即可,这也很想Django中的{% url 'name' 参数 %}
IV、自定义状态码
常见的状态码有200,404,500等,我们如何自定义这种状态码呢?
# python中return可一次返回多个对象
@app.route('/demo')
def demo8():
return '自定义状态码', 666
我们重启服务,进入http://127.0.0.1:5000/demo8
然后检查网页NetWork,刷新页面
V、路由正则匹配
我们在Django中实现路由的正则常用的有url、path、repath,那么我们如何在Flask内也同样实现路由的匹配呢?
我们先新建一个app_new.py然后设置它运行端口为5020
from flask import Flask
app = Flask(__name__)
if __name__ == '__main__':
app.run(port=5020, debug=True)
进行路由自定义匹配时需要以下四步
1、导入转换器基类(在flask内,所有的路由匹配规则都是使用转换器对象进行记录的)
2、自定义转换器继承BaseConverter
3、添加转换器到默认的字典中
4、使用自定义转换器实现自定义规则匹配
# 导入转换器基类
from werkzeug.routing import BaseConverter
这里就不得不提及先前我们编写的@app.route('/user/<int:user_id>')
内的<int>
转换器的实现,我们进入routing的文件中,在1342行下:
DEFAULT_CONVERTERS = {
# 默认转换器
"default": UnicodeConverter,
"string": UnicodeConverter,
# 其余转换器
"any": AnyConverter,
"path": PathConverter,
"int": IntegerConverter,
"float": FloatConverter,
"uuid": UUIDConverter,
}
该处定义了@app.route('< converter >')
的所有可选转换器项,其中我们以<int>
为例介绍一下该处的转换器。根据"int": IntegerConverter
,确定<int`>``对应的转换器类为
IntegerConverter查看
class IntegerConverter(NumberConverter)是基于
NumberConverter类实现的,而
NumberConverter类是基于
BaseConverter类实现的。
<int>的实现便基于转换器类,而不是传统python内自带的
int()```转换函数
①自定义转换器类基于基类
class RegexConverter(BaseConverter):
# url_map:路径的映射
def __init__(self, url_map, *args):
super(RegexConverter, self).__init__(url_map)
# 将第一个参数当做匹配规则进行保存(不写死匹配规则)
self.regex = args[0]
为何可以通过super()
调用父类后添加map参数呢?我们再来回顾一下routing下BaseConverter类的代码
class BaseConverter(object):
"""Base class for all converters."""
regex = "[^/]+"
weight = 100
def __init__(self, map):
self.map = map
②将转换器添加到默认字典DEFAULT_CONVERTERS内
app.url_map.converters['re'] = RegexConverter
③使用自定义转换器实现自定义规则匹配
@app.route('/users/<re("[0-9]{3}"):users_id>')
def user_infos(users_id):
return 'user_id {}'.format(users_id)
④运行服务后输入在浏览器内输入http://127.0.0.1:5020/users/33,http://127.0.0.1:5020/users/333,http://127.0.0.1:5020/users/3333 观察匹配的结果
注:传入re规则的第一个参数需要是string类型,因此需要加引号 <re("匹配规则"):匹配参数名>
回顾以上操作,我们可以思考一下<re>转换器是如何实现调用的
1、首先是在默认字典DEFAULT_CONVERTERS内查找re对应的转换器类 ——“re”:RegexConverter
2、调用RegexConverter类内的regex方法获取匹配的规则
3、根据规则进行匹配需要的参数
VI、异常捕获
我们新建一个demo_ext.py,利用pycharm的Edit Configuration内的Addition options使它运行在127.0.0.1:5001端口下
from flask import Flask
app = Flask(__name__)
if __name__ == '__main__':
app.run(debug=True)
我们先主动抛出一个异常状态
from flask import abort
@app.route('/')
def index():
# abort(500)
abort(404)
return 'haha'
启动服务,观察网页状态
注:abort只能抛出HTTP协议规范的异常状态码,如404,500等
我们也可以捕获异常,需要使用装饰器的方式,如下是捕获500异常的函数
@app.errorhandler(500)
def errohandler_sever():
return '服务器出现了错误了'
当然我们可以修改一下index函数来抛出新的异常,如除零异常:
@app.route('/')
def index():
a = 0
# 该处出现除零异常ZeroDivisionError
b = 1 / a
return 'haha'
# 编辑捕获ZeroDivisionError的函数
@app.errorhandler(ZeroDivisionError)
def zeroDivisionError(error):
return "除数不可为0"
运行该服务观察页面提示