在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ 信號(hào)
應(yīng)用環(huán)境
配置管理
大型應(yīng)用
可插撥視圖
Flask 方案
在 Shell 中使用 Flask
針對(duì)高級(jí)程序員的前言
使用藍(lán)圖的模塊化應(yīng)用
部署方式
信號(hào)
排除應(yīng)用錯(cuò)誤
模板
請(qǐng)求環(huán)境
掌握應(yīng)用錯(cuò)誤
測(cè)試 Flask 應(yīng)用
前言
教程
安裝
快速上手
Flask 擴(kuò)展

信號(hào)

New in version 0.6.

Flask 自 0.6 版本開始在內(nèi)部支持信號(hào)。信號(hào)功能由優(yōu)秀的 blinker 庫提供支持, 如果沒有安裝該庫就無法使用信號(hào)功能,但不影響其他功能。

什么是信號(hào)?當(dāng)核心框架的其他地方或另一個(gè) Flask 擴(kuò)展中發(fā)生動(dòng)作時(shí),信號(hào)通過發(fā)送 通知來幫助你解耦應(yīng)用。簡(jiǎn)言之,信號(hào)允許某個(gè)發(fā)送者通知接收者有事情發(fā)生了。

Flask 自身有許多信號(hào),其他擴(kuò)展可能還會(huì)帶來更多信號(hào)。請(qǐng)記住,信號(hào)使用目的是通知 接收者,不應(yīng)該鼓勵(lì)接收者修改數(shù)據(jù)。你會(huì)注意到信號(hào)的功能與一些內(nèi)建的裝飾器類似( 如 request_started 與 before_request() 非常 相似),但是它們的工作原理不同。例如核心的 before_request() 處理器以一定的順序執(zhí)行,并且可以提前退出請(qǐng)求,返回一個(gè)響應(yīng)。相反,所有的信號(hào)處理器是亂序執(zhí)行的,并且不修改任何數(shù)據(jù)。

信號(hào)的最大優(yōu)勢(shì)是可以安全快速的訂閱。比如,在單元測(cè)試中這些臨時(shí)訂閱十分有用。 假設(shè)你想知道請(qǐng)求需要渲染哪個(gè)模塊,信號(hào)可以給你答案。

訂閱信號(hào)

使用信號(hào)的 connect() 方法可以訂閱該信號(hào)。該方法的 第一個(gè)參數(shù)是當(dāng)信號(hào)發(fā)出時(shí)所調(diào)用的函數(shù)。第二個(gè)參數(shù)是可選參數(shù),定義一個(gè)發(fā)送者。 使用 disconnect() 方法可以退訂信號(hào)。

所有核心 Flask 信號(hào)的發(fā)送者是應(yīng)用本身。因此當(dāng)訂閱信號(hào)時(shí)請(qǐng)指定發(fā)送者,除非你真的 想要收聽?wèi)?yīng)用的所有信號(hào)。當(dāng)你正在開發(fā)一個(gè)擴(kuò)展時(shí),尤其要注意這點(diǎn)。

下面是一個(gè)環(huán)境管理器的輔助工具,可用于在單元測(cè)試中辨別哪個(gè)模板被渲染了,哪些變量被傳遞給了模板:

from flask import template_rendered
from contextlib import contextmanager

@contextmanager
def captured_templates(app):
    recorded = []
    def record(sender, template, context, **extra):
        recorded.append((template, context))
    template_rendered.connect(record, app)
    try:
        yield recorded
    finally:
        template_rendered.disconnect(record, app)

上例可以在測(cè)試客戶端中輕松使用:

with captured_templates(app) as templates:
    rv = app.test_client().get('/')
    assert rv.status_code == 200
    assert len(templates) == 1
    template, context = templates[0]
    assert template.name == 'index.html'
    assert len(context['items']) == 10

為了使 Flask 在向信號(hào)中添加新的參數(shù)時(shí)不發(fā)生錯(cuò)誤,請(qǐng)確保使用一個(gè)額外的 **extra 參數(shù)。

在 with 代碼塊中,所有由 app 渲染的模板會(huì)被記錄在 templates 變量中。每當(dāng)有模板被渲染,模板對(duì)象及環(huán)境就會(huì)追加到變量中。

另外還有一個(gè)方便的輔助方法( connected_to() )。它允許臨時(shí)把一個(gè)使用環(huán)境對(duì)象的函數(shù)訂閱到一個(gè)信號(hào)。因?yàn)榄h(huán)境對(duì)象的返回值不能被指定,所以必須把列表作為參數(shù):

from flask import template_rendered

def captured_templates(app, recorded, **extra):
    def record(sender, template, context):
        recorded.append((template, context))
    return template_rendered.connected_to(record, app)

上例可以這樣使用:

templates = []
with captured_templates(app, templates, **extra):
    ...
    template, context = templates[0]

Blinker API 變化

Blinker version 1.1 版本中增加了 connected_to() 方法。

創(chuàng)建信號(hào)

如果相要在你自己的應(yīng)用中使用信號(hào),那么可以直接使用 blinker 庫。最常見的,也是最推薦的方法是在自定義的 Namespace 中命名信號(hào):

from blinker import Namespace
my_signals = Namespace()

接著可以像這樣創(chuàng)建新的信號(hào):

model_saved = my_signals.signal('model-saved')

信號(hào)的名稱應(yīng)當(dāng)是唯一的,并且應(yīng)當(dāng)簡(jiǎn)明以便于調(diào)試??梢酝ㄟ^ name 屬性獲得信號(hào)的名稱。

擴(kuò)展開發(fā)者注意

如果你正在編寫一個(gè) Flask 擴(kuò)展,并且想要妥善處理 blinker 安裝缺失的情況,那么可以使用 flask.signals.Namespace 類。

發(fā)送信號(hào)

如果想要發(fā)送信號(hào),可以使用 send() 方法。它的第一個(gè)參數(shù)是一個(gè)發(fā)送者,其他參數(shù)要發(fā)送給訂閱者的東西,其他參數(shù)是可選的:

class Model(object):
    ...

    def save(self):
        model_saved.send(self)

請(qǐng)謹(jǐn)慎選擇發(fā)送者。如果是一個(gè)發(fā)送信號(hào)的類,請(qǐng)把 self 作為發(fā)送者。如果發(fā)送信號(hào)的是一個(gè)隨機(jī)的函數(shù),那么可以把 current_app._get_current_object() 作為發(fā)送者。

傳遞代理作為發(fā)送者

不要把 current_app 作為發(fā)送者傳遞給信號(hào)。請(qǐng)使用 current_app._get_current_object() 。因?yàn)?current_app 是 一個(gè)代理,不是實(shí)際的應(yīng)用對(duì)象。

信號(hào)與 Flask 的請(qǐng)求環(huán)境

信號(hào)在接收時(shí),完全支持請(qǐng)求環(huán)境 。在 request_started 和 request_finished 本地環(huán)境變量 始終可用。因此你可以依賴 flask.g 及其他本地環(huán)境變量。 請(qǐng)注意在 發(fā)送信號(hào) 中所述的限制和 request_tearing_down 信號(hào)。

信號(hào)訂閱裝飾器

Blinker 1.1 版本中你還可以通過使用新的 connect_via() 裝飾器輕松訂閱信號(hào):

from flask import template_rendered

@template_rendered.connect_via(app)
def when_template_rendered(sender, template, context, **extra):
    print 'Template %s is rendered with %s' % (template.name, context)

核心信號(hào)

Flask 中有以下信號(hào):

flask.template_rendered 這個(gè)信號(hào)發(fā)送于一個(gè)模板被渲染成功后。信號(hào)傳遞的 template 是模板的實(shí)例, context 是環(huán)境對(duì)象是一個(gè)字典。

訂閱示例:

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)
flask.request_started

這個(gè)信號(hào)發(fā)送于請(qǐng)求開始之前,且請(qǐng)求環(huán)境設(shè)置完成之后。因?yàn)檎?qǐng)求環(huán)境已經(jīng)綁定, 所以訂閱者可以用標(biāo)準(zhǔn)的全局代理,如 request 來操作請(qǐng)求。

訂閱示例:

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

這個(gè)信號(hào)發(fā)送于向客戶端發(fā)送響應(yīng)之前。信號(hào)傳遞的 response 為將要發(fā)送的響應(yīng)。

訂閱示例:

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

這個(gè)信號(hào)發(fā)送于請(qǐng)求進(jìn)行中發(fā)生異常的時(shí)候。它的發(fā)送早于標(biāo)準(zhǔn)異常處理介于。 在調(diào)試模式下,雖然沒有異常處理,但發(fā)生異常時(shí)也發(fā)送這個(gè)信號(hào)。信號(hào)傳遞的 exception 是異常對(duì)象。

訂閱示例:

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

這個(gè)信號(hào)發(fā)送于請(qǐng)求崩潰的時(shí)候,不管是否引發(fā)異常。目前,偵聽此信號(hào)的函數(shù)在一般崩潰處理器后調(diào)用,但是沒有什么東西可用。

訂閱示例:

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 中,這還會(huì)傳遞一個(gè) exc 關(guān)鍵字參數(shù),如果這個(gè)參數(shù)存在的話。 這個(gè)參數(shù)是引發(fā)崩潰的異常的引用。

flask.appcontext_tearing_down 當(dāng)應(yīng)用環(huán)境崩潰時(shí)發(fā)送這個(gè)信號(hào)。這個(gè)信號(hào)總是會(huì)發(fā)送,甚至是因?yàn)橐粋€(gè)異常引發(fā)的 崩潰。偵聽這個(gè)信號(hào)的函數(shù)會(huì)在常規(guī)崩潰處理器后被調(diào)用,但是你無法回饋這個(gè)信號(hào)。

訂閱示例:

def close_db_connection(sender, **extra):
    session.close()

from flask import request_tearing_down
appcontext_tearing_down.connect(close_db_connection, app)

這還會(huì)傳遞一個(gè) exc 關(guān)鍵字參數(shù),如果這個(gè)參數(shù)存在的話。這個(gè)參數(shù)是引發(fā)崩潰的異常的引用。

flask.appcontext_pushed 當(dāng)一個(gè)應(yīng)用的環(huán)境被壓入時(shí),應(yīng)用會(huì)發(fā)送這個(gè)信號(hào)。這個(gè)信號(hào)通常用于在單元測(cè)試中臨時(shí)鉤接信息。例如可以用于改變 g 對(duì)象中現(xiàn)存的資源。

用法示例:

from contextlib import contextmanager
from flask import appcontext_pushed

@contextmanager
def user_set(app, user):
    def handler(sender, **kwargs):
        g.user = user
    with appcontext_pushed.connected_to(handler, app):
        yield

在測(cè)試代碼中這樣寫:

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.

appcontext_popped

當(dāng)一個(gè)應(yīng)用的環(huán)境被彈出時(shí),應(yīng)用會(huì)發(fā)送這個(gè)信號(hào)。這個(gè)信號(hào)通常寫成 appcontext_tearing_down 信號(hào)。

New in version 0.10.

flask.message_flashed 當(dāng)應(yīng)用閃現(xiàn)一個(gè)消息時(shí)會(huì)發(fā)出這個(gè)信號(hào)。message參數(shù)是消息內(nèi)容, category 參數(shù)是消息類別。

訂閱示例:

recorded = []
def record(sender, message, category, **extra):
    recorded.append((message, category))

from flask import message_flashed
message_flashed.connect(record, app)
New in version 0.10.

? Copyright 2013, Armin Ronacher. Created using Sphinx.