Flask路由分析
from flask import Flask
app = Flask(__name__)
@app.route('/home')
def func():
return "hello world"
# 在flask源码中调用的就是add_url_rule方法,并把url和函数名传进去
# app.add_url_rule("/home", view_func=func)
app.run()
------------------------------------------
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop("endpoint", None)
# rule= '/index',endpoint=None,f=func,**options={}
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
@setupmethod
def add_url_rule(
self,
rule, # rule= '/index'
endpoint=None,
view_func=None, # view_func=func函数名
provide_automatic_options=None,
**options
):
if endpoint is None:
# _endpoint_from_view_func函数返回了view_func.__name__,也就是'func'
endpoint = _endpoint_from_view_func(view_func)
options["endpoint"] = endpoint # {"endpoint":'func'}
methods = options.pop("methods", None) # methods = None
if methods is None:
# 若是func函数中没有定义methods变量就,默认使用GET
methods = getattr(view_func, "methods", None) or ("GET",) # methods = ("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=set('get')
# Methods that should always be added
required_methods = set(getattr(view_func, "required_methods", ()))
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 # False
# Add the required methods now.
methods |= required_methods
# rule = Role('/index',methods=('get'),{"endpoint":'func'})
# role对象.role='/index'
rule = self.url_rule_class(rule, methods=methods, **options) # ***********重点
# Map对象.add(role对象)
self.url_map.add(rule)
if view_func is not None:
# {}
old_func = self.view_functions.get(endpoint)
# {'func字符串':func函数名}
self.view_functions[endpoint] = view_func
@implements_to_string
class Rule(RuleFactory):
def __init__(
self,
string, # '/index',
endpoint, # 'func'
):
self.rule = string # role对象.role = '/index'
self.methods = set([x.upper() for x in methods]) # {"GET"}
if "HEAD" not in self.methods and "GET" in self.methods:
self.methods.add("HEAD") # {"GET","HEAD"}
self.endpoint = endpoint
def bind(self, map, rebind=False):
"""能够不看"""
self.map = map # 把map对象封装到role对象里 即role.map = map对象
self.strict_slashes = map.strict_slashes # self.strict_slashes = True
self.subdomain = map.default_subdomain # self.subdomain = ""
self.compile()
class Map(object):
def add(self, rulefactory):
"""
:param rulefactory: role对象
:return:
"""
for rule in rulefactory.get_rules(self):
# 如今的rule是role对象
rule.bind(self) # self是map对象
self._rules.append(rule) # 空列表加入rule对象
# {}.setdefault(rule.endpoint, []).append(rule)
# {'func字符串':[rule对象,]}
# {endpoint:[rule对象,]}
self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule)
self._remap = True
从上面的源码分析中得出:
# app.view_functions = {'func字符串':func函数地址}
# app.map对象._rules_by_endpoint = [rule对象,]
# role对象.role = '/index'
1. app里封装了一个字典,字典中的键位:endpoint,值为函数名
{
endpoint:函数名
}
2. app里封装了一个map对象,在map对象中封装了字典,字典的key为endpoint字符串,value为列表,列表里放Role对象
2.1 role对象里封装了url
Map对象(
{'endpoint':[Role对象,]}
)