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對象,]}
)