一、flask转换器
前面文章中所遇到的都是简单路由,而且是固定的路由,本篇文章来讲解一下动态路由,还有正则路由,以及如何自定义路由转换器。
二、动态路由
动态路由主要指需要传入参数的路由。
在flask中,参数默认是string,但是也可以指定其他类型,比如数字int等。
变量名需要传入装饰的视图函数中,格式为:
@app.route('xxx/< converter:variable_name>')
def yyy(variable_name):
pass
其中convert
是转换器,flask中主要有以下4种基本类型转换器:
类型 | 说明 |
---|---|
string | 默认,可以不用写 |
int | 接受整数 |
float | 同int,但是接受浮点数 |
path | 和默认的string相似,但接受斜线 |
@app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % username
@app.route('/post/<int:post_id>')
def show_post(post_id):
# show the post with the given id, the id is an integer
return 'Post %d' % post_id
二、基础转换器:BaseConverter
现在有个需求,如果需要传入的URL参数是一个正则式的匹配结果。
那么怎么办呢?基于上面的思路,我们发现如果传入的参数的格式是依赖于转换器的:
- 如果是整数形式,有int转换器,
- 如果是字符串,则默认string转换器,
这么看来,那么有没有一个方法能实现某个正则转换器呢?
当然有啦,下面来一起看看。
1.BaseConverter
类
Flask中所有的转换器,包括之前的int、float、path等都会继承一个BaseConverter的类;而且BaseConverter类是隐形支持正则。
BaseConverter
在 flask 中的werkzeug
的routing
包里。
现在我们进入源码去看看BaseConvert类:
class BaseConverter(object):
"""Base class for all converters."""
regex = "[^/]+"
weight = 100
def __init__(self, map):
self.map = map
def to_python(self, value):
return value
def to_url(self, value):
if isinstance(value, (bytes, bytearray)):
return _fast_url_quote(value)
return _fast_url_quote(text_type(value).encode(self.map.charset))
源码分析:
个人见解,未必正确,如有错误,还麻烦贵人能私信我,让我也改正错误,谢谢!
-
- BaseConvert类中其实定义了2个类属性,
-
regex
:默认regex="[^/]+
,定义了一个map是指当前映射。 -
weight
:值为100
- 初始化函数,给每个实例使用初始化传入参数map
- 4.实例方法:
to_python
to_python
方法是将函数解析过程交给类a+b -> [a,b],使用场景没使用url_for
to_python
方法的作用: 将你传过去的参数转换成对应类型的数据,比如你设置传参是uuid类型数据,那么当你传参以后,就会调用to_python
方法,将参数转换为对应的uuid类型。调用
to_python
时: 函数执行的是首先装饰器正则匹配提取出id ,然后id当成value传给to_python
,经to_python
处理交给视图函数,相当于如果可以某个url的参数进行一些其他操作,然后传递给视图函数。
- 实例方法:
to_url
- 实例方法:
to_url
方法:to_python
方法,实现了url中的参数的分割或者一些操作,url_for则是将分割和操作后的参数继续拼接成原来的URL.
也就是说,to_url
方法定义了如何给url反向解析的时候显示你传入的参数.
2. 反向解析路径
学习反向解析路径,可以帮助我们更加理解BaseConverter
中的to_url
和to_python
方法。
- flask中使用url_for来反向解析
from flask import url_for
# url_for根据别名来反向解析获取路由
url = url_for(endpoint指定的别名(视图函数的名字))
- 举个例子
@app.route("/hello")
def hello():
"""欢迎页"""
return "hello flask"
@app.route("/index", methods=['GET', 'POST'])
def index():
"""首页"""
url = url_for("hello")
print(url)
return "这是首页"
输出如下:
/hello
关于带转换器的URL的反向解析
当通过反向解析传递函数时:
- a. 首先
url_for
传递给函数to_url
- b.
to_url
函数对传入value值进行处理交给装饰器- c. 调用
to_python
方法,按照规则提取参数- d. 传入到视图函数中,执行并返回响应
三、自定义正则转换器
1、编写自定义转换器方法:
- 自定义类,继承
BaseConverter
类
- 编写初始化方法, init方法, 接收两个参数, url_map, regex, 并初始化父类空间和子类空间
- 将自定义转换器类,添加到默认的转换列表中
class MyRegexConverter(BaseConverter):
# 2.编写初始化方法, init方法, 接收两个参数, url_map, regex,
def __init__(self,url_map,regex):
super(MyRegexConverter, self).__init__(url_map) # 初始化父类空间和子类空间
self.regex = regex # 定义正则表达式字段
2、使用自定义转换器
- 1、使用
app.url_map.converters
字典,给这个字典添加某个key,然值为你定义的转换器类名- 2、
<key(参数):variable_name>
# 3.将自定义转换器类,添加到默认的转换列表中
app.url_map.converters['re'] = MyRegexConverter
#使用自定义转换器
#接收3位整数
@app.route('/<re("\d{3}"):num>')
def hello_world(num):
print("num = %s"%num)
return "the num is %s"%num
四、拓展
此外,下面还有 PathConverter
、UUIDConverter
等,再往下,我们会看到,原来这里写好了一个映射,每当我们在url中传入指定类型的参数时,系统会自动的来寻找这里的映射:
#: the default converter mapping for the map.
DEFAULT_CONVERTERS = {
"default": UnicodeConverter,
"string": UnicodeConverter,
"any": AnyConverter,
"path": PathConverter,
"int": IntegerConverter,
"float": FloatConverter,
"uuid": UUIDConverter,
}
-
那么我们现在想自定义url转换器——我们希望传入的是list类型的数据,那么我们就可以参照上面代码里的形式,定义
to_python
和to_url
方法,并添加到DEFAULT_CONVERTERS
映射中去。 -
现在我们假定获取到的参数是[1, 2, 3],我们要把它以1+2+3的形式在url中,那么我们to_python方法的任务就是将url中的1+2+3中的 +去掉;我们知道python的split方法可以去掉 +,但是它返回的是一个list列表,而url中地址不可能出现列表,即你不可能看到过地址是127.0.0.1:500/[1,2,3]/这种形式,所以我们另一个任务就是将数组转换成我们需要的
1+2+3
这种形式。
注意: 我们的url地址参数是在代码里传的就是flask.url_for('detail', params=[1, 2, 3]),就是说通过url_for传递参数函数。
网友评论