在 Web 应用中,接口一般都是遵守 RESTful API 设计风格的,这种风格很优雅,而且对用户来说非常易于理解。
RESTful API 参考: RESTful Web APIs设计风格
通过网络接口,程序员可以跳过 Web 的首页或导航页,直接访问到需要访问的页面,直接获取想要的数据。
在 Web 的后端,处理数据和返回数据的是视图函数,接口需要通过路由来映射到指定的视图函数上。
在 Flask 框架中,提供了 route() 装饰器来实现路由,使用 route() 装饰视图函数,在 route() 中传入该视图函数对应的 API 。使用装饰器的方式来实现路由非常方便,开发时可以集中精力来处理业务逻辑,加上装饰器就完成了接口和视图函数的映射关系。
一、Flask 中 route() 的基本使用
使用之前创建好的 FlaskProject 虚拟环境,项目文件名也叫 FlaskProject ,在 FlaskProject 目录下创建一个 flask_route.py 文件,编写后端的视图函数。
代码语言:javascript复制from flask import Flask, render_template
app = Flask(__name__)
@app.route('/index')
def index():
return render_template('route_one.html')
if __name__ == '__main__':
app.run()
app 是实例化的 Flask APP 对象,通过 app.route() 来装饰视图函数。
在 route() 函数中,传入了参数 ‘/index’ ,说明当访问 /index 接口时,对应的后端视图函数是 index() 函数。访问 /index 获取到的响应内容就是 index() 函数返回的数据。
在上面的视图函数中返回了模板文件 route_one.html ,在 FlaskProject 目录下提前创建好了一个叫 templates 的模板文件夹,在模板文件夹中编写 route_one.html 模板文件。
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Route</title>
</head>
<body>
<p style="color: blue"> Hello Jinja2 ! </p>
</body>
</html>
运行上面的 flask_route.py 程序,在前端访问 http://127.0.0.1:5000/index ,就可以访问到 route_one.html 页面。
二、在路由中传参
在上面的例子中, route() 中传入的 API 是硬编码“写死”的。
在很多场景下,需要用一个视图函数来动态返回数据,路由将 API 中的动态部分传递给视图函数,视图函数再根据参数动态地返回数据。
这种方式在 route() 中已经实现了,可以使用 route('<arg>') 的方式来传参。
在上面的 flask_route.py 中增加一个视图函数。修改如下:
代码语言:javascript复制from flask import Flask, render_template
app = Flask(__name__)
@app.route('/index')
def index():
return render_template('route_one.html')
@app.route('/phone/<num>')
def phone(num):
return render_template('route_one.html', num=num)
if __name__ == '__main__':
app.run(debug=True)
在模板文件 route_one.html 中增加一个显示数据的标签。修改如下:
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Route</title>
</head>
<body>
<p style="color: blue"> Hello Jinja2 ! </p>
<p style="color: blue"> Phone {{ num }} </p>
</body>
</html>
重新运行 flask_route.py ,在前端访问 /phone/<num> ,就可以将 num 从 url 传给路由,从路由传给视图函数,从视图函数传给模板文件,最终由模板文件展示在前端的页面上。
如访问 http://127.0.0.1:5000/phone/777 ,页面效果如下:
上面使用路由传递的参数是整数,但 route() 会默认当做 string 处理,默认会转换成字符串。上面只是用整数来作为例子,实际使用时,可以根据需求来指定传递的数据类型。
指定数据类型的方式为:route('/<数据类型:变量名>') ,如指定 num 参数是整数类型:route('/<int:num>') 。指定 int 后,route() 会将 url 中传过来的参数转换成 int 再传给视图函数。
三、正则匹配路由
在通过路由传递参数时,可以指定参数的数据类型,在 Flask 中,这种功能是通过转换器来实现的,转换器会按照定义的规则来转换或匹配参数。
Flask 自带的转换器有以下这些:
代码语言:javascript复制DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}
可以直接调用这些自带的转换器,也可以自定义转换器,如定义一个用正则来匹配的转换器,通过正则匹配路由。
正则可以对访问的路由进行匹配,满足规则才能访问成功。
自定义转换器的步骤为:
1. 导入 werkzeug 中的转换器基类,自定义的转换器需要继承 Flask 的 werkzeug 工具集中的转换器基类。
2. 自定义一个类继承于转换器基类,在类中重写转换器基类的 __init__ 方法,并定义正则转换器的第一个参数作为正则匹配规则。
3. 将正则转换器添加到默认的转换器字典 DEFAULT_CONVERTERS 中。
4. 在 route() 装饰器中使用正则转换器实现自定义匹配规则,在转换器后面传给正则转换器第一个参数,这个参数就是正则匹配规则。
继续在 flask_route.py 中添加代码,修改后如下:
代码语言:javascript复制from flask import Flask, render_template
from werkzeug.routing import BaseConverter
app = Flask(__name__)
@app.route('/index')
def index():
return render_template('route_one.html')
@app.route('/phone/<num>')
def phone(num):
return render_template('route_one.html', num=num)
class RegexConverter(BaseConverter):
def __init__(self, url_map, *args):
super(RegexConverter, self).__init__(url_map)
self.regex = args[0]
app.url_map.converters['re'] = RegexConverter
@app.route('/phones/<re("w "):num>')
def phone_size(num):
return render_template('route_one.html', num=num)
if __name__ == '__main__':
app.run(debug=True)
代码中先从 werkzeug.routing 导入了 BaseConverter,然后定义 RegexConverter 类继承 BaseConverter,url_map 参数是 Flask app 对象将自定义转换器添加到 DEFAULT_CONVERTERS 的方法,self.regex = args[0] 表示将这个类接收到的第一个参数作为正则规则。
使用 app.url_map.converters['re'] = RegexConverter 将自定义转换器注册到默认转换器字典中,在字典中 key 是 re ,value 是 RegexConverter,使用时通过 key 来调用。
使用 route() 装饰视图函数时,在 re() 内传入正则规则,如:route('/phones/<re("w "):num>') 表示 num 需要满足 w 正则规则。
模板文件继续使用 route_one.html ,不做修改。
重新运行 flask_route.py ,在前端访问 /phones/<num> ,num 需要满足正则 w ,才能请求到 phone_size() 视图函数。
如访问 http://127.0.0.1:5000/phones/Plus ,页面效果如下: