flask route支持正则

需求

flask跟web.py差别挺大的,尤其是在路由管理这块。web.py把所有的路由都集中在一起,我比较喜欢这种方式。最近用flask,发现@app.route(‘‘)中URL只支持string、int、float、path 4种类型,并不支持正则.

方案

通过运行如下代码

1
2
3
4
5
6
from flask import Flask
from pprint import pprint
if __name__ == '__main__':
app = Flask(__name__)
pprint(app.url_map.converters)

可以获取Flask默认支持的转换器

1
2
3
4
5
6
7
{'any': <class 'werkzeug.routing.AnyConverter'>,
'default': <class 'werkzeug.routing.UnicodeConverter'>,
'float': <class 'werkzeug.routing.FloatConverter'>,
'int': <class 'werkzeug.routing.IntegerConverter'>,
'path': <class 'werkzeug.routing.PathConverter'>,
'string': <class 'werkzeug.routing.UnicodeConverter'>,
'uuid': <class 'werkzeug.routing.UUIDConverter'>}

那如何创建一个新的路由解析转化器呢?
在Flask的app.py里有个简单的例子,这个例子是创建了一个regex类型的路由转换器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: Ycan
# About: http://www.ehco.me/
# Email: yoncan@qq.com
from flask import Flask
from werkzeug.routing import BaseConverter
class RegexConverter(BaseConverter):
""" 支持正则的路由判断
Example::
Rule('/<regex(r"\d+"):lang_code>')
:param map: the :class:`Map`.
"""
def __init__(self, map, *args):
BaseConverter.__init__(self, map)
self.regex = args[0]
def to_python(self, value):
return value
app = Flask(__name__)
app.url_map.converters['regex'] = RegexConverter
@app.route('/test/<regex(r"[a-z]\d+$"):user>', methods=['GET'])
def test_regex_route(user):
"""
:param user:
:return:
url请求 /test/a10001
result: user=a10001
"""
return 'get user: {0}'.format(user)
if __name__ == '__main__':
app.run()

总结

Flask(其实是Werkzeug)使用Converter把URL中特殊部分(<regex(r"[a-z]\d+$"):user>)转换为Python变量,通用格式是。在这个例子中,一个叫regex的converter把URL中相应字段转换为view()中的user变量。

因此,converter的regex就是用来判断这串字符是否符合转换格式,ok就转换,否则跳过。对于IntegerConverter来说,”abc”显然无能为力。也就是说,其实Werkzeug的路由本来就支持用正则表达式。string、int、float等都是从它派生出来的(可以看看IntegerConverter等built-in Converter的regex)。

至于为什么不显式地支持,我猜可能是因为正则表达式不容易写好,buggy。

分享即快乐,谢谢你请思哲小朋友吃糖!