路由,就是将URL
和Function
对应起来,
可以将URL
作为key,将Function
作为value.但是flask
中并不是这么简单.
flask
中构建路由有两种方法:
1.app.add_url_rule
2.@app.route()
@app.route()
的本质是调用了app.add_url_rule
Basically this example::
@app.route('/')
def index():
pass
Is equivalent to the following::
def index():
pass
app.add_url_rule('index', '/')
app.view_functions['index'] = index
app.add_url_rule
有三个参数:
rule
:url字符串
endpoint
:的id
options
:是werkzeug.routing.Rule
的参数
def add_url_rule(self, rule, endpoint, **options):
options['endpoint'] = endpoint
options.setdefault('methods', ('GET',)) # 将默认的请求方法设置为`Get`
self.url_map.add(Rule(rule, **options)
可以看到,通过操作url_map
也可以实现,url_map
本质是werkzeug
库中的Map
对象,还调用了werkzeug
的Rule
对象.
from werkzeug.routing import Map, Rule
self.url_map = Map()
首先看Map
>>> m = Map([
... Rule('/', endpoint='index'),
... Rule('/downloads/', endpoint='downloads/index'),
... Rule('/downloads/<int:id>', endpoint='downloads/show')
... ])
>>> urls = m.bind("example.com", "/")
>>> urls.match("/", "GET")
('index', {})
>>> urls.match("/downloads/42")
('downloads/show', {'id': 42})
Map
的主要作用就是URL
和endpoint
的映射,通过URL
来找(match)endpoint
.而如何通过endpoint
找function
则需要我们自己来实现,flask
中是用字典来实现的
当我们写下:
@app.route('/')
def index():
pass
首先是调用self.add_url_rule
添加路由规则,endpoint
是function
的名字,这里是index
,
然后在view_functions
(dict)中添加,key
是function
的名字,value
是function
方法
def route(self, rule, **options):
def decorator(f):
self.add_url_rule(rule, f.__name__, **options)
self.view_functions[f.__name__] = f
return f
return decorator
view_functions
是flask
初始化时创建的
self.view_functions = {}
而在处理请求的时候,也是直接在view_functions
中根据endpoint
来提取
def dispatch_request(self):
try:
endpoint, values = self.match_request() # 根据url获得endpoint
return self.view_functions[endpoint](**values) # 根据endpoint来调用方法
except HTTPException, e:
handler = self.error_handlers.get(e.code)
if handler is None:
return e
return handler(e)
except Exception, e:
handler = self.error_handlers.get(500)
if self.debug or handler is None:
raise
return handler(e)
最后补充werkzeug
实现的match
方法
def match(self, path):
if not self.build_only:
m = self._regex.search(path)
if m is not None:
groups = m.groupdict()
result = {}
for name, value in iteritems(groups):
try:
value = self._converters[name].to_python(value)
except ValidationError:
return
result[str(name)] = value
if self.defaults:
result.update(self.defaults)
return result
参考:
https://cizixs.com/2017/01/12/flask-insight-routing/