参考及转载
- flask/app.py-add_url_rule源码分析
一、add_url_rule源码
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
methods = options.pop('methods', None) # if the methods are not given and the view_func object knows its
# methods we can use that instead. If neither exists, we go with
# a tuple of only ``GET`` as default.
if methods is None:
methods = getattr(view_func, 'methods', None) or ('GET',) if isinstance(methods, string_types): raise TypeError('Allowed methods have to be iterables of strings, '
'for example: @app.route(..., methods=["POST"])')
methods = set(item.upper() for item in methods) # Methods that should always be added
required_methods = set(getattr(view_func, 'required_methods', ())) # starting with Flask 0.8 the view_func object can disable and
# force-enable the automatic options handling.
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 # Add the required methods now.
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
二、参数解析:
-
rule
: 一个字符串格式的url规则,如:"/login".
注:就是从
route
方法中调用add_url_rule
是传递的rule
.
-
endpoint
: url规则的名字,用来反向生成url使用,默认是视图函数的名字。
注:如果是
route
方法调用的,则这个参数是route
方法传递过来的endpoint
的值,在route
中应该传递的方式是endpoint=xxx
.
-
view_func
: 视图函数,当对应的endpoint名字被请求时需要调用的函数。
注:如果是
router
方法调用的add_url_rule
,则这个参数时router
方法传递过来的view_func
.
-
options
: 类似与分析route
时候的options
.这个options是跟随:class:~werkzeug.routing.Rule
object定义的,后面会分析这个对象中的具体参数,但有一个methods参数默认是只监听get方法。
注:如果是
router
方法点用的add_url_rule
,则这个参数时router
方法传递过来的options
函数.
三、函数体解析:
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
if endpoint is None:
# 如果没有提供endpoint参数,则默认用view_func的名字
endpoint = _endpoint_from_view_func(view_func)
# 把endpoint参数添加到options里面
options['endpoint'] = endpoint
# 从options中pop出methods参数,并把值赋给methods变量,如果没有则置为None
methods = options.pop('methods', None)
# moehods的值为None的情况下
if methods is None:
# 如果view_func函数中有这个methods参数,则使用view_func中的。如果没有则赋一个列表('GET',)给methods
methods = getattr(view_func, 'methods', None) or ('GET',)
# 如果methods是字符串类型
if isinstance(methods, string_types):
# 抛出一个异常:methods需要是一个可以迭代的字符串
raise TypeError('Allowed methods have to be iterables of strings, '
'for example: @app.route(..., methods=["POST"])')
# 把methods里面的item都改成大写
methods = set(item.upper() for item in methods)
# 在view_func里面定义了一个属性required_methods = ()
# 作用:用来定义一些必须的方法,配合provide_automatic_options使用
required_methods = set(getattr(view_func, 'required_methods', ()))
# starting with Flask 0.8 the view_func object can disable and
# force-enable the automatic options handling.
# 在view_func里面定义了一个属性provide_automatic_options = None
# 作用:用于禁用和强制启用一些自动选项
provide_automatic_options = getattr(view_func,
'provide_automatic_options', None)
# 判断provide_automati_options是否为None
if provide_automatic_options is None:
# 如果OPTIONS字符串没有在methods里面
if 'OPTIONS' not in methods:
# 则把provude_automatic_options改为True,并把OPTIONS添加到required_methods里面
provide_automatic_options = True
required_methods.add('OPTIONS')
# 如果OPTIONS在methods里面,则把provide_automatic_options设置为False
else:
provide_automatic_options = False
# 合并required_methods和methods这两个集合到methods里面
methods |= required_methods
# 创建路由规则
# 调用url_rule_class方法,由于在Flask类的全局变量中定义了:url_rule_class = Rule, Rule是werkzeug/routing.py里面的一个类
# 也就是相当于实例化了Rule得到了rule对象,具体实例化后的结果请看Rule源码分析
rule = self.url_rule_class(rule, methods=methods, **options)
# 把provide_automatic_options属性添加到rule对象里面
rule.provide_automatic_options = provide_automatic_options
# 在Flask类的__init__里面定义了self.url_map = Map(),Map是werkzeug/routing.py里面的一个类
# self.url_map相当与实例化了Map,.add则是调用了Map类里面的add方法
# 具体运行结果,请参考Map源码分析,以及Map源码中的add方法分析
self.url_map.add(rule)
# 如果提供了view_func
if view_func is not None:
# 在flask类的__init__里面定义了self.view_functions = {},
# 从字典里面取endpoint值并赋值为old_func,(endpoint是传递的参数,默认为视图函数名)
old_func = self.view_functions.get(endpoint)
# 如果old_func有值,并且不等于view_func
if old_func is not None and old_func != view_func:
# 则抛出异常:视图函数映射被一个已经存在的函数名重写了
# 也就是说已经存在了一个endpoint:old_func的映射,但是old_fun却不是view_func,也就是说endpoint重复了
raise AssertionError('View function mapping is overwriting an '
'existing endpoint function: %s' % endpoint)
# 添加视图函数与endpoint映射到view_functions字典里面
self.view_functions[endpoint] = view_func