flask 蓝图的钩子

上一篇介绍了flask 的钩子,这一篇介绍一下蓝图的钩子,不要感到奇怪,Blueprint是为了能够在大型应用中对众多业务模块进行API分层次管理,因此一个blueprint也有实用钩子的必要。

1. 钩子存储在哪?

蓝图的钩子和app的钩子,联系非常紧密,首先,我们看一下,app的钩子都存储在哪里了,以before_request为例

@app.before_request
def app_before_request():
    print('app_before_request')

跟踪代码,看一下before_request的源码

    @setupmethod
    def before_request(self, f):
        self.before_request_funcs.setdefault(None, []).append(f)
        return f

app的钩子被注册在了app的before_request_funcs里,现在,看一下蓝图的before_request

@blue.before_request
def add_blue_before_request():
    print('只在蓝图内生效')

跟踪代码,看一下蓝图的before_request源码

    def before_request(self, f):
        self.record_once(
            lambda s: s.app.before_request_funcs.setdefault(self.name, []).append(f)
        )
        return f

同app的钩子一样,也存储在app的before_request_funcs里,它是一个字典,app的钩子存储时以None做key,蓝图的钩子存储时,以蓝图的名称做key,这就是他们的不同。

2. 蓝图都有哪些钩子装饰器

  1. before_request
  2. after_request
  3. teardown_request
  4. teardown_appcontext
  5. before_app_request
  6. after_app_request
  7. before_app_first_request

先来看后三个名称里有app的,这三个钩子装饰器,完全等同于于app的before_request, after_request和before_first_request,这三个装饰器将钩子函数注册到app.before_request_funcs里,用None做key。这样安排,是为了在各个蓝图里,可以对全局的请求做一些处理前后的操作。

既然蓝图的before_app_request等于app的before_request, 那么蓝图自身的before_request装饰器有什么用呢? before_request,after_request,teardown_request 蓝图的这3个钩子都只在蓝图内生效,请求如果不在蓝图的处理范围内,这些钩子函数不会被执行。如此,每个蓝图的可以只针对自身的请求做一些个性化的处理,而不会影响到其他蓝图。

最后说teardown_appcontext, 它等价于app的teardown_appcontext, 作用范围是整个app。

下表是蓝图钩子的生效范围

装饰器 生效范围
before_request 蓝图
after_request 蓝图
teardown_request 蓝图
teardown_appcontext 全局
before_app_request 全局
after_app_request 全局
before_app_first_request 全局

3. 理论联系实践

第二小节里,讲解了蓝图钩子的生效范围,下面实际验证理论

from flask import Flask, Blueprint


app = Flask(__name__)

blue = Blueprint('user', __name__, url_prefix='/user')

@blue.before_app_request
def add_app_before_request():
    print('整个app生效')


@blue.before_request
def add_blue_before_request():
    print('只在蓝图内生效')

@blue.route('/info')
def info():
    return '小明'

app.register_blueprint(blue)

@app.before_request
def app_before_request():
    print('app_before_request')


@app.route('/')
def index():
    return 'hello'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5500)

代码里,app和blue都使用before_request

  1. 如果请求是http://127.0.0.1:5500/,那么会输出“app_before_request”, 不会输出 “只在蓝图内生效”
  2. 如果请求是http://127.0.0.1:5500/user/info, 则“app_before_request” 与 “只在蓝图内生效” 均输出

实际验证与理论推论一致。

app与蓝图的before_request究竟哪个先执行,与注册顺序无关,app的优先级高于蓝图,先执行app注册的钩子函数,后执行蓝图注册的钩子函数。

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案