该模块实现了Flask的蓝图,最主要的是定义了BlueprintSetupState和Blueprint类,实现了和路由相关的一些方法,但实质都是调用的app.py中Flask类中的方法。
class BlueprintSetupState(object):
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
if self.url_prefix: #给url加上前缀
rule = self.url_prefix + rule
options.setdefault('subdomain', self.subdomain)
if endpoint is None: #返回视图函数的名字 endpoint =view_func.__name__
endpoint = _endpoint_from_view_func(view_func)#返回视图函数的名字
defaults = self.url_defaults
if 'defaults' in options:
defaults = dict(defaults, **options.pop('defaults'))
#这里实质还是调用了app的add_url_rule
self.app.add_url_rule(rule, '%s.%s' % (self.blueprint.name, endpoint),
view_func, defaults=defaults, **options)
为了便于理解,我改变了源码中定义函数的顺序。
class Blueprint(_PackageBoundObject):
"""通过@blueprint.route这个带参数的装饰器定义路由的时候,装饰器通过
endpoint = options.pop("endpoint", f.__name__)语句找到了endpoint"""
def route(self, rule, **options): #把视图函数添加到蓝图中,实质是调用add_url_rule
def decorator(f):
endpoint = options.pop("endpoint", f.__name__)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
if endpoint:
assert '.' not in endpoint, "Blueprint endpoint's should not contain dot's"
self.record(lambda s: s.add_url_rule(rule, endpoint, view_func, **options))
#最后一句话很重要:这里调用了record,并以一个匿名函数当做参数,该匿名函数又包含了rule, endpoint, view_func, **options等信息,即对应一个视图函数。
def record(self, func):
if self._got_registered_once and self.warn_on_modifications:
from warnings import warn
warn(Warning('The blueprint was already registered once '
'but is getting modified now. These changes '
'will not show up.'))
self.deferred_functions.append(func)
#这里承接上面的add_url_rule,往deferred_functions这个列表里添加了匿名函数,而这个匿名函数就对应着一个视图函数。
def register(self, app, options, first_registration=False):
"""在Flask.register_blueprint里调用 ,往app里注册"""
self._got_registered_once = True
#state是BlueprintSetupState实例,记录了蓝图注册是的各种状态信息
state = self.make_setup_state(app, options, first_registration)
#state = make_setup_state实例化了一个BlueprintSetupState
if self.has_static_folder:
state.add_url_rule(self.static_url_path + '/<path:filename>',
view_func=self.send_static_file,
endpoint='static')
for deferred in self.deferred_functions:
deferred(state)
"""这里的deferred_functions就是上个函数record添加的视图函数的列表。
而deferred 就是上面record添加的匿名函数:lambda s: s.add_url_rule(rule, endpoint, view_func, **options),
而"deferred(state) "把state当做实参,等同于state.add_url_rule
state是BlueprintSetupState的实例对象,所以这里上下面都是调用BlueprintSetupState的add_url_rule方法,上文中提到最终实质还是调用app的add_url_rule
所以循环deferred_functions,所有视图函数都会通过BlueprintSetupState的add_url_rule方法也就是app的add_url_rule,添加到app中"""