Flask 提供了信號(Signals)功能,是一種消息分發機制。類似于鉤子(Hooks)。使用信號功能可以降低程序的耦合,分解復雜的業務模型。例如在更新了產品數據后,可以發送一個信號。當有需要對產品數據進行處理的功能時,就可以捕獲信號進行處理。比如要建立產品緩存,或是更新搜索索引等。
定義信號
Flask 信號功能使用了 Blinker 模塊,所以需要先安裝 Blinker 模塊
1
|
pip install blinker |
定義一個信號:
1
2
|
from blinker import Namespace product_saved = Namespace() |
也可以使用 Flask 包裝的 singles 對象:
1
|
from flask.singles import Namespace |
發送信號
發送信號需要帶上 app 實例方法,示例如下:
1
|
product_saved.send(app, product = product) |
app 后面可以添加要傳遞的參數,但必須以 name=value 的格式,不支持使用單個變量名的方式。
收接信號
接收信號可以使用 connect_via 裝飾器函數:
1
2
3
|
@product_saved .connect_via(app) def updateCache(app, product): print (product) |
Flask 中有以下核心信號:
1.flask.template_rendered
這個信號發送于一個模板被渲染成功后。信號傳遞的template是模板的實例,context是環境對象是一個字典。
訂閱示例:
1
2
3
4
5
6
|
def log_template_renders(sender, template, context, * * extra): sender.logger.debug( 'Rendering template "%s" with context %s' , template.name or 'string template' , context) from flask import template_rendered template_rendered.connect(log_template_renders, app) |
2.flask.request_started
這個信號發送于請求開始之前,且請求環境設置完成之后。因為請求環境已經綁定, 所以訂閱者可以用標準的全局代理,如 request 來操作請求。
訂閱示例:
1
2
3
4
5
|
def log_request(sender, * * extra): sender.logger.debug( 'Request context is set up' ) from flask import request_started request_started.connect(log_request, app) flask.request_finished |
這個信號發送于向客戶端發送響應之前。信號傳遞的response為將要發送的響應。
訂閱示例:
1
2
3
4
5
6
|
def log_response(sender, response, * * extra): sender.logger.debug( 'Request context is about to close down. ' 'Response: %s' , response) from flask import request_finished request_finished.connect(log_response, app) flask.got_request_exception |
這個信號發送于請求進行中發生異常的時候。它的發送 早于 標準異常處理介于。 在調試模式下,雖然沒有異常處理,但發生異常時也發送這個信號。信號傳遞的exception是異常對象。
訂閱示例:
1
2
3
4
5
|
def log_exception(sender, exception, * * extra): sender.logger.debug( 'Got exception during processing: %s' , exception) from flask import got_request_exception got_request_exception.connect(log_exception, app) flask.request_tearing_down |
這個信號發送于請求崩潰的時候,不管是否引發異常。目前,偵聽此信號的函數在一般 崩潰處理器后調用,但是沒有什么東西可用。
訂閱示例:
1
2
3
|
def close_db_connection(sender, * * extra): session.close() from flask import appcontext_tearing_down request_tearing_down.connect(close_db_connection, app) |
在 Flask 版本 0.9 中,這還會傳遞一個exc關鍵字參數,如果這個參數存在的話。 這個參數是引發崩潰的異常的引用。
3.flask.appcontext_tearing_down
當應用環境崩潰時發送這個信號。這個信號總是會發送,甚至是因為一個異常引發的 崩潰。偵聽這個信號的函數會在常規崩潰處理器后被調用,但是你無法回饋這個信號。
訂閱示例:
1
2
3
|
def close_db_connection(sender, * * extra): session.close() from flask import request_tearing_down appcontext_tearing_down.connect(close_db_connection, app) |
這還會傳遞一個exc關鍵字參數,如果這個參數存在的話。這個參數是引發崩潰的 異常的引用。
4.flask.appcontext_pushed
當一個應用的環境被壓入時,應用會發送這個信號。這個信號通常用于在單元測試中 臨時鉤接信息。例如可以用于改變g對象中現存的資源。
用法示例:
1
2
3
4
5
6
7
|
from contextlib import contextmanagerfrom flask import appcontext_pushed @contextmanagerdef user_set(app, user): def handler(sender, * * kwargs): g.user = user with appcontext_pushed.connected_to(handler, app): yield |
在測試代碼中這樣寫:
1
2
3
4
5
6
|
def test_user_me( self ): with user_set(app, 'john' ): c = app.test_client() resp = c.get( '/users/me' ) assert resp.data = = 'username=john' New in version 0.10 . |
5.appcontext_popped
當一個應用的環境被彈出時,應用會發送這個信號。這個信號通常寫成appcontext_tearing_down 信號。
6.flask.message_flashed
當應用閃現一個消息時會發出這個信號。message`參數是消息內容, `category參數是消息類別。
訂閱示例:
1
2
3
4
|
recorded = [] def record(sender, message, category, * * extra): recorded.append((message, category)) from flask import message_flashed message_flashed.connect(record, app) |
小結
信號可以讓你在一瞬間安全地訂閱它們。例如,這些臨時的訂閱對測試很有幫助。使用信號時,不要讓信號訂閱者(接收者)發生異常,因為異常會造成程序中斷。