看这篇文章以前,建议看一下我以前写的: flask中路由匹配是如何实现的
BluePrint(蓝图)的概念说白了就是路由组,全部注册到该蓝图上的路由都使用同一个前缀。这样方便了管理,不一样的功能能够放在一个模块(好比admin模块)中实现,更加解耦。html
首先来看看蓝图是如何使用的:python
# 定义一个蓝图 simple_page = Blueprint('simple_page', __name__, template_folder='templates') # 绑定视图函数 @simple_page.route('/', defaults={'page': 'index'}) @simple_page.route('/<page>') def show(page): try: return render_template('pages/%s.html' % page) except TemplateNotFound: abort(404) # 在主模块中注册路由 app = Flask(__name__) app.register_blueprint(simple_page)
看上面的例子,首先定义了一个蓝图simple_page,而后经由这个蓝图来定义路由以及绑定到视图函数上,最后在主模块中,注册这个蓝图便可。flask
看起来跟常见的定义视图函数的方式同样,只不过在添加路由的时候,须要以蓝图开头。app
来看看源码中是如何实现的。函数
蓝图的功能是在flask 0.7版本中被加入的,app在调用 register_blueprint 方法的时候会调用 Blueprint 类中的 register 方法来注册该蓝图中添加的全部路由。url
def register_blueprint(self, blueprint, **options): ... blueprint.register(self, options, first_registration)
咱们看一下register方法:设计
# blueprints.py def register(self, app, options, first_registration=False): ... state = self.make_setup_state(app, options, first_registration) ... for deferred in self.deferred_functions: deferred(state)
额,make_setup_state是个啥,deferred_functions又是个啥。咱们跳到make_setup_state来看看它里面有什么:code
def make_setup_state(self, app, options, first_registration=False): return BlueprintSetupState(self, app, options, first_registration)
返回了一个类。先无论。来看看deferred_functions是什么,从名字上能够看出是延迟函数之类的。htm
来梳理一下流程,app.register_blueprint 注册蓝图以后,会激活Buleprint类中的register方法,在register方法中循环调用 deferred_functions 中的函数来执行,咱们大概能猜出来这段代码的功能就是将蓝图中定义的路由都添加到路由组中。blog
以上面的蓝图例子,
@simple_page.route('/', defaults={'page': 'index'})
蓝图的route方法是这样的:
def route(self, rule, **options): def decorator(f): self.add_url_rule(rule, f.__name__, f, **options) return f return decorator
route方法是个装饰器,实际上调用了 add_url_rule 方法:
def add_url_rule(self, rule, endpoint=None, view_func=None, **options): self.record(lambda s: s.add_url_rule(rule, endpoint, view_func, **options)) def record(self, func): .... self.deferred_functions.append(func)
在record方法中,将func添加到了deferred_functions列表中,而add_url_rule中调用了record方法,那么一切就均可以解释了:
register 方法中的这段代码,
state = self.make_setup_state(app, options, first_registration) ... for deferred in self.deferred_functions: deferred(state)
循环 deferred_functions,deferred_functions 里面是啥?是lambda,具体来讲,就是蓝图中定义的路由和视图函数,咱们经过
@simple_page.route('/<page>')
定义路由以后,实际上就是在 deferred_functions 里面添加了一个lambda,为何说它是defer,由于只有在register注册的时候才会真正添加到app的url_map中。
上面代码中的state是一个 BlueprintSetupState 示例,这个类里面有一个add_url_rule方法,会在全局app的 url_map 中添加路由和视图函数。
def add_url_rule(self, rule, endpoint=None, view_func=None, **options): self.app.add_url_rule(rule, '%s.%s' % (self.blueprint.name, endpoint),view_func, defaults=defaults, **options)
来梳理一下:
# state 是 BlueprintSetupState 实例 BlueprintSetupState -> state # deferred_functions 里面是蓝图路由的lambda lambda s: s.add_url_rule -> deferred_functions for deferred in self.deferred_functions: deferred(state) 意思就是 lambda 中的 s 被赋值为 state ,而后state.add_url_rule, 这样就执行了app.add_url_rule
这个延迟执行设计的太巧妙了,蓝图中添加的路由规则只有在register方法中才真正的被添加到全局的路由map中。
个人blog: https://blog.shiniao.fun/