Flask route的源码分析
flask的例子
from flask import Flask
app = Flask(__name__)
@app.route('/',methods=['GET'])
def index():
return "hello world"
if __name__ == '__main__':
app.run()
使用app.route装饰器,完成了url与视图函数的映射
在flask中使用了werkzueg的Rule类、Map类和MapAdapter类实现了{url:endpoint:view_func}的映射关系
route装饰器在app.py的Flask类中
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop('endpoint', None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
通过装饰器将url传入到add_url_rule当中的rule,methods以**options关键字参数传入到add_url_rule中
def add_url_rule(self, rule, endpoint=None, view_func=None,
provide_automatic_options=None, **options):
在add_url_rule中,判断endpoint是否为空,为空调用_endpoint_from_view_func函数从视图函数中以字符串取出视图函数名,并将endpoint添加到字典options当中
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
options['endpoint'] = endpoint
methods = options.pop('methods', None)
_endpoint_from_view_func函数返回视图函数的__name__属性
def _endpoint_from_view_func(view_func):
assert view_func is not None, 'expected view func if endpoint '\
'is not provided.'
return view_func.__name__
将rule、methods、**options传入Rule类构造出一个rule对象,将该rule对象添加到url_map当中.其中 options['endpoint']=endpoint, rule=url . 通过routing.py的Rule类建立了(url,endpoint,methods)的映射关系
rule = self.url_rule_class(rule, methods=methods, **options)
self.url_map.add(rule)
url_map是routing.py的Map类创建出来的一个对象,用来存储Rule的对象
self.url_map = Map()
Map内以列表来存储Rule的对象
url_map = Map([
Rule('/all/', defaults={'page': 1}, endpoint='all_entries'),
Rule('/all/page/<int:page>', endpoint='all_entries')
])
add_url_rule的view_func就是app.route构造器修饰的视图函数,app.py的Flask类定义了view_functions为一个空字典,将view_func存入view_functions中,建立了{endpoint:view_func}的映射关系
if view_func is not None:
old_func = self.view_functions.get(endpoint)
if old_func is not None and old_func != view_func:
raise AssertionError('View function mapping is overwriting an '
'existing endpoint function: %s' % endpoint)
self.view_functions[endpoint] = view_func
Flask的url_map存储了所有的(url,endpoint)映射关系;
Flask的view_functions存储了所有的{endpoint:view_func}映射关系;
至此,url与视图函数就通过endpoint映射起来了,请求时服务器对请求进行转发,解析得到url,通过MapAdapter类的match方法得到endpoint,再通过view_functions找到对应的视图函数,直接调用函数执行,就完成了一个完整的route.