追本朔源弄清楚@app.route
后面到底发生了什么。
理解以备注的形式写在源码上,截取的源码只有相关的片段。
一、app.route
的定义
找到app.route
:
app.route
调用了app的route
函数来装饰一个view函数
app
是Flask
类的实例,创建于app = Flask(__name__)
二、Flask类的定义
2.1 找到Flask类
先直接找到class Flask
:
1 2 3 4 5 6 7 8 9 10 11 12 13 class Flask (_PackageBoundObject ): ... def __init__ (self, import_name, static_path=None , static_url_path=None , static_folder='static' , template_folder='templates' , instance_path=None , instance_relative_config=False ): _PackageBoundObject.__init__(self, import_name, template_folder=template_folder) self.view_functions = {} ... ...
找到_PackageBoundObject
类:
1 2 3 4 5 6 class _PackageBoundObject (object ): def __init__ (self, import_name, template_folder=None ): self.import_name = import_name self.template_folder = template_folder ...
2.2 Flask类的route
函数
再看看route
函数的作用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Flask (_PackageBoundObject ): ... 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 ...
2.3 Flask类的add_url_rule
函数
通过上面分析可以知道route
函数主要是对add_url_rule
函数的调用:
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 49 50 51 52 53 54 @setupmethod def add_url_rule (self, rule, endpoint=None , view_func=None , **options ): if endpoint is None : endpoint = _endpoint_from_view_func(view_func) options['endpoint' ] = endpoint 从options字典中获取methods methods = options.pop('methods' , None ) if methods is None : methods = getattr (view_func, 'methods' , None ) or ('GET' ,) methods = set (methods) required_methods = set (getattr (view_func, 'required_methods' , ())) provide_automatic_options = getattr (view_func, 'provide_automatic_options' , None ) if provide_automatic_options is None : if 'OPTIONS' not in methods: provide_automatic_options = True required_methods.add('OPTIONS' ) else : provide_automatic_options = False methods |= required_methods ... rule = self.url_rule_class(rule, methods=methods, **options) rule.provide_automatic_options = provide_automatic_options self.url_map.add(rule) 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
看看setupmethod
函数做了什么:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 def setupmethod (f ): def wrapper_func (self, *args, **kwargs ): if self.debug and self._got_first_request: raise AssertionError('A setup function was called after the ' 'first request was handled. This usually indicates a bug ' 'in the application where a module was not imported ' 'and decorators or other functionality was called too late.\n' 'To fix this make sure to import all your view modules, ' 'database models and everything related at a central place ' 'before the application starts serving requests.' ) return f(self, *args, **kwargs) return update_wrapper(wrapper_func, f)
2.4 Flask实例的url_rule_class
和url_map
1 2 3 4 5 6 7 8 9 10 11 class Flask (_PackageBoundObject ): ... url_rule_class = Rule ... def __init__ (... ): ... self.url_map = Map() ...
三、本文总结
总结和@app.route
相关的引用以及其作用。
3.1 Flask类
Flask类基于_PackageBoundObject
,其实_PackageBoundObject
类也只是初始化import_name
和template_folder
这个属性,方便文件路径处理。
Flask实例有一个view_functions
字典,里面的key=value记录了该实例的view_func
,key为view_func
的endpoint
(默认为函数名称,也可以在route函数的参数中指定), value为函数本身。
3.2 route
函数
route
函数是一个装饰器,会从参数中获取endpoin
t(如果没有则为None),并把rule
, endpoint
, 和被装饰的函数等作为参数传给add_url_rule
函数。
route
函数的核心还是add_url_rule
函数。
3.3 add_url_rule
函数
首先会试图从参数或者函数名称中获取endpoint。
然后从参数或者view_func
属性中获取methods。
然后调用Flask
实例的url_rule_class
, 这是一个Rule类。传入rule
, methods
和view_func
剩下的其它参数,实例化一个Rule
类。
再调用Flask实例的url_map
,这是一个Map
类的实例。 调用这个类的add
函数,传入刚才实例化的Rule
类。
3.4 Rule
类和Map
类
Rule
和Map
都是werkzeug库routing模块下的类。
一个Flask app 通常都有一个Map
实例,里面包含若干在add_url_rule
函数中被创建的Rule
实例。
在收到一个Request
之后,通常会遍历Map
实例,获得请求路径与其对应的view_func,从而触发对应的函数。