Flask信号机制

信号是 Flask 中一项非常强大的功能。从软件工程角度讲,可以让数据传递代码彼此解耦;从功能实现角度讲,可以在某个事件发生时,就自动执行一系列的配套操作。下面分别讲解自定义信号和 Flask 内置信号。

自定义信号

Flask 从 0.6 版本开始就支持信号机制。信号的作用是在发生某个事情时,直接通知某个函数执行,可以达到代码间解耦的作用。Flask 中的信号是通过第三方库 blinker 实现的。我们先来学习一下如何创建信号以及发送信号,创建信号的示例代码如下。

from blinker import Namespace

# 定义Namespace对象
my_signals = Namespace()

# 创建名称为model-saved的信号
model_saved = my_signals.signal('model-saved')

上述代码中,首先是创建了一个 Namespace 对象 my_signals,然后通过 my_signals.signal 方法添加了一个名称为 model-saved 的信号。接着还需要订阅此信号,也就是在发生此信号时,需要执行什么代码,示例代码如下。

def log_model_saved(sender):
    print("捕获到信号,发送者为:{}".format(sender))

my_signals.connect(log_model_saved)

上述代码中,首先通过 my_signals.connect 方法订阅信号,在信号产生后,会执行 log_model_saved 方法。然后在其他代码中如有需要的情况,就可以通过 my_signals.send 来发送信号了,示例代码如下。

class Model(object):
    ...
    def save(self):
        model_saved.send(self)

上述代码中,model_save.send 方法中的第 1 个参数是发送者,在订阅的函数中可以通过 sender 参数获取发送者的信息。

Flask内置信号

flask 中已经提前内置了许多信号,在相应的事件发生后,会发送信号,我们只需监听即可。在监听的时候,可以设置只接收哪个发送者发送的信号,一般设置为 app。下面来介绍常用的信号。

flask.template_rendered

模板渲染完毕后会发送此信号,示例代码如下。

from flask import template_rendered

def log_template_renders(sender, template, context, *args):
    print('sender:', sender)
    print('template:', template)
    print('context:', context)

template_rendered.connect(log_template_renders, app)

flask.request_started

在接收到请求且到达视图函数之前会发送此信号,示例代码如下。

def log_request_started(sender, **extra):
    print('sender:', sender)
    print('extra:', extra)

request_started.connect(log_request_started, app)

flask.request_finished

请求结束后,在响应发送到客户端之前会发送此信号,示例代码如下。

def log_request_finished(sender, response, *args):
    print('response:', response)

request_finished.connect(log_request_finished, app)

flask.got_request_exception

在请求过程中出现异常时会发送此信号,示例代码如下。

def log_exception_finished(sender, exception, *args):
    print('sender:', sender)
    print(type(exception))

got_request_exception.connect(log_exception_finished, app)

flask.request_tearing_down

请求完成后,在对象被销毁之前会发送此信号。即使请求过程中发生异常,也会发送此信号,示例代码如下。

def log_request_tearing_down(sender, **kwargs):
    print('coming...')

request_tearing_down.connect(log_request_tearing_down, app)