研究一下Flask的app.route到底做了什么工作
@index.route('/') def hello_world(): # import inspect, json # print(json.dumps([str(fi.frame) for fi in inspect.stack()], indent=4)) return render_template('test_jinja.html'), 404
跟踪route
装饰器
# Scaffold类中 def route(self, rule: str, **options: t.Any) -> t.Callable: def decorator(f: t.Callable) -> t.Callable: endpoint = options.pop("endpoint", None) self.add_url_rule(rule, endpoint, f, **options) return f return decorator
发现其实只是调用了一个add_url_rule
所以我们可以通过add_url_rule
直接添加路由而不使用装饰器。
app.add_url_rule(rule, endpoint, f, **options)
跟踪add_url_rule
#Scaffold类中 @setupmethod def add_url_rule( self, rule: str, endpoint: t.Optional[str] = None, view_func: t.Optional[t.Callable] = None, provide_automatic_options: t.Optional[bool] = None, **options: t.Any, ) -> None: raise NotImplementedError
这个函数在Scaffold
中是空的,看来在Flask
有它的override
跟进Flask.add_url_rule
# Flask类中 @setupmethod def add_url_rule( self, rule: str, endpoint: t.Optional[str] = None, view_func: t.Optional[t.Callable] = None, provide_automatic_options: t.Optional[bool] = None, **options: t.Any, ) -> None: # 获取endpoint,如果为空则取函数名 if endpoint is None: endpoint = _endpoint_from_view_func(view_func) # type: ignore # 设置endpoint options["endpoint"] = endpoint # method为HTTP动作的元组或列表,如['GET', 'POST'] methods = options.pop("methods", None) # 如果为空,则寻找这个view_func的methods属性 # 否则默认是('GET'),即默认只处理GET动作 if methods is None: methods = getattr(view_func, "methods", None) or ("GET",) # method不能是字符串 if isinstance(methods, str): raise TypeError( "Allowed methods must be a list of strings, for" ' example: @app.route(..., methods=["POST"])' ) # 将methods的所有元素转为大写,即能够在methods参数中使用小写,如('get', 'post'),因为这里有转换 methods = {item.upper() for item in methods} # Methods that should always be added # 必须要添加的HTTP动作 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. # 是否自动添加options动作 if provide_automatic_options is None: 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 # type: ignore # 将规则添加到url_map中 self.url_map.add(rule) if view_func is not None: # 不同视图必须有不同的endpoint,即endpoint唯一,是不同视图的标识符 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" f" endpoint function: {endpoint}" ) # 将视图存入view_functions self.view_functions[endpoint] = view_func
这个函数最终处理下来主要做了两件事
url_rule_class
类(Rule
类),并存入url_map
(一个为url服务的Map
类型)view_func
存入view_functions
(一个字典类型)