django 1.8 官方文檔翻譯: 3-6-1 中間件概覽

Django 文檔協(xié)作翻譯小組人手緊缺表蝙,有興趣的朋友可以加入我們缺虐,完全公益性質(zhì)。

交流群:467338606

網(wǎng)站:http://python.usyiyi.cn/django/index.html

中間件

中間件是一個(gè)介入Django的請(qǐng)求和響應(yīng)的處理過(guò)程中的鉤子框架步氏。它是一個(gè)輕量級(jí)滑沧,底層的“插件”系統(tǒng),用于在全局修改Django的輸入或輸出躬它。

中間件組件責(zé)任處理某些特殊的功能腾啥。例如,Django包含一個(gè)中間件組件冯吓,AuthenticationMiddleware 碑宴,使用會(huì)話將用戶和請(qǐng)求關(guān)聯(lián)。

這篇文檔講解了中間件如何工作桑谍,如何激活中間件延柠,以及如何編寫自己的中間件。Django集成了一些內(nèi)置的中間件可以直接開箱即用锣披。它們被歸檔在 內(nèi)置中間件參考.

激活中間件

要激活一個(gè)中間件組件贞间,需要把它添加到你Django配置文件中的MIDDLEWARE_CLASSES 列表中。

在MIDDLEWARE_CLASSES中雹仿,每一個(gè)中間件組件用字符串的方式描述:一個(gè)完整的Python全路徑加上中間件的類名稱增热。例如,使用 django-admin startproject創(chuàng)建工程的時(shí)候生成的默認(rèn)值:

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
)

Django的程序中胧辽,中間件不是必需的 — 只要你喜歡峻仇,MIDDLEWARE_CLASSES可以為空 — 但是強(qiáng)烈推薦你至少使用CommonMiddleware。

MIDDLEWARE_CLASSES中的順序非常重要邑商,因?yàn)橐粋€(gè)中間件可能依賴于另外一個(gè)摄咆。例如,AuthenticationMiddleware在會(huì)話中儲(chǔ)存已認(rèn)證的用戶人断。所以它必須在SessionMiddleware之后運(yùn)行吭从。一些關(guān)于Django中間件類的順序的常見提示,請(qǐng)見Middleware ordering恶迈。

鉤子和應(yīng)用順序

在請(qǐng)求階段中涩金,調(diào)用視圖之前,Django會(huì)按照MIDDLEWARE_CLASSES中定義的順序自頂向下應(yīng)用中間件。會(huì)用到兩個(gè)鉤子:

  • process_request()
  • process_view()

在響應(yīng)階段中步做,調(diào)用視圖之后副渴,中間件會(huì)按照相反的順序應(yīng)用,自底向上全度。會(huì)用到三個(gè)鉤子:

  • process_exception() (僅當(dāng)視圖拋出異常的時(shí)候)
  • process_template_response() (僅用于模板響應(yīng))
  • process_response()

如果你愿意的話煮剧,你可以把它想象成一顆洋蔥:每個(gè)中間件都是包裹視圖的一層“皮”。

每個(gè)鉤子的行為接下來(lái)會(huì)描述讼载。

編寫自己的中間件

編寫自己的中間件很容易的轿秧。每個(gè)中間件組件是一個(gè)單獨(dú)的Python的class,你可以定一個(gè)或多個(gè)下面的這些方法:

process_request

process_request(request)

request是一個(gè)HttpRequest 對(duì)象咨堤。

在Django決定執(zhí)行哪個(gè)視圖(view)之前菇篡,process_request()會(huì)被每次請(qǐng)求調(diào)用。

它應(yīng)該返回一個(gè)None 或一個(gè)HttpResponse對(duì)象一喘。如果返回 None, Django會(huì)繼續(xù)處理這個(gè)請(qǐng)求驱还,執(zhí)行其他process_request()中間件,然后process_view()中間件顯示對(duì)應(yīng)的視圖凸克。如果它返回一個(gè)HttpResponse對(duì)象议蟆,Django便不再會(huì)去調(diào)用其他的請(qǐng)求(request), 視圖(view)或其他中間件,或?qū)?yīng)的視圖萎战;處理HttpResponse的中間件會(huì)處理任何返回的響應(yīng)(response)咐容。

process_view

process_view(request, view_func, view_args, view_kwargs)

request是一個(gè)HttpRequest對(duì)象。view_func是 Django會(huì)調(diào)用的一個(gè)Python的函數(shù)蚂维。(它確實(shí)是一個(gè)函數(shù)對(duì)象戳粒,不是函數(shù)的字符名稱。) view_args是一個(gè)會(huì)被傳遞到視圖的位置參數(shù)列表虫啥,而view_kwargs 是一個(gè)會(huì)被傳遞到視圖的關(guān)鍵字參數(shù)字典蔚约。 view_args和 view_kwargs 都不包括第一個(gè)視圖參數(shù)(request)。

process_view()會(huì)在Django調(diào)用視圖(view)之前被調(diào)用涂籽。

它將返回None 或一個(gè)HttpResponse 對(duì)象苹祟。如果返回 None,將會(huì)繼續(xù)處理這個(gè)請(qǐng)求评雌,執(zhí)行其他的process_view() 中間件树枫,然后顯示對(duì)應(yīng)的視圖。如果返回HttpResponse對(duì)象柳骄,Django就不再會(huì)去調(diào)用其他的視圖(view)团赏,異常中間件(exception middleware)或?qū)?yīng)的視圖 ;它會(huì)把響應(yīng)中間件應(yīng)用到HttpResponse上耐薯,并返回結(jié)果。

注意

在中間件內(nèi)部,從process_request或者process_view方法中訪問(wèn)request.POST或者request.REQUEST將會(huì)阻礙該中間 件之后的所有視圖無(wú)法修改request的上傳處理程序曲初, 一般情況要避免這樣使用体谒。

類CsrfViewMiddleware可以被認(rèn)為是個(gè)例外 ,因?yàn)樗峁┝薱srf_exempt() 和 csrf_protect()兩個(gè)允許視圖來(lái)精確控制 在哪個(gè)點(diǎn)需要開啟CSRF驗(yàn)證臼婆。

process_template_response

process_template_response(request, response)

request是一個(gè)HttpRequest對(duì)象抒痒。response是一個(gè)TemplateResponse對(duì)象(或等價(jià)的對(duì)象),由Django視圖或者中間件返回颁褂。

如果響應(yīng)的實(shí)例有render()方法故响,process_template_response()在視圖剛好執(zhí)行完畢之后被調(diào)用,這表明了它是一個(gè)TemplateResponse對(duì)象(或等價(jià)的對(duì)象)颁独。

這個(gè)方法必須返回一個(gè)實(shí)現(xiàn)了render方法的響應(yīng)對(duì)象彩届。它可以修改給定的response對(duì)象,通過(guò)修改 response.template_name和response.context_data或者它可以創(chuàng)建一個(gè)全新的 TemplateResponse或等價(jià)的對(duì)象誓酒。

你不需要顯式渲染響應(yīng) —— 一旦所有的模板響應(yīng)中間件被調(diào)用樟蠕,響應(yīng)會(huì)自動(dòng)被渲染。

在一個(gè)響應(yīng)的處理期間靠柑,中間件以相反的順序運(yùn)行寨辩,這包括process_template_response()。

process_response

process_response(request, response)

request是一個(gè)HttpRequest對(duì)象歼冰。response是Django視圖或者中間件返回的HttpResponse或者StreamingHttpResponse對(duì)象靡狞。

process_response()在所有響應(yīng)返回瀏覽器之前被調(diào)用。

這個(gè)方法必須返回HttpResponse或者StreamingHttpResponse對(duì)象隔嫡。它可以改變已有的response甸怕,或者創(chuàng)建并返回新的HttpResponse或StreamingHttpResponse對(duì)象。

不像 process_request()和process_view()方法畔勤,即使同一個(gè)中間件類中的process_request()和process_view()方法會(huì)因?yàn)榍懊娴囊粋€(gè)中間件返回HttpResponse而被跳過(guò)蕾各,process_response()方法總是會(huì)被調(diào)用。特別是庆揪,這意味著你的process_response()方法不能依賴于process_request()方法中的設(shè)置式曲。

最后,記住在響應(yīng)階段中缸榛,中間件以相反的順序被應(yīng)用吝羞,自底向上。意思是定義在MIDDLEWARE_CLASSES最底下的類會(huì)最先被運(yùn)行内颗。

處理流式響應(yīng)

不像HttpResponse钧排,StreamingHttpResponse并沒有content屬性。所以均澳,中間件再也不能假設(shè)所有響應(yīng)都帶有content屬性恨溜。如果它們需要訪問(wèn)內(nèi)容符衔,他們必須測(cè)試是否為流式響應(yīng),并相應(yīng)地調(diào)整自己的行為糟袁。

if response.streaming:
    response.streaming_content = wrap_streaming_content(response.streaming_content)
else:
    response.content = alter_content(response.content)

注意

我們需要假設(shè)streaming_content可能會(huì)大到在內(nèi)存中無(wú)法容納判族。響應(yīng)中間件可能會(huì)把它封裝在新的生成器中,但是一定不要銷毀它项戴。封裝一般會(huì)實(shí)現(xiàn)成這樣:

def wrap_streaming_content(content):
    for chunk in content:
        yield alter_content(chunk)

process_exception

process_exception(request, exception)

request是一個(gè)HttpRequest對(duì)象形帮。exception是一個(gè)被視圖中的方法拋出來(lái)的 Exception對(duì)象。

當(dāng)一個(gè)視圖拋出異常時(shí)周叮,Django會(huì)調(diào)用process_exception()來(lái)處理辩撑。process_exception()應(yīng)該返回一個(gè)None 或者一個(gè)HttpResponse對(duì)象。如果它返回一個(gè)HttpResponse對(duì)象仿耽,模型響應(yīng)和響應(yīng)中間件會(huì)被應(yīng)用合冀,響應(yīng)結(jié)果會(huì)返回給瀏覽器。Otherwise, default exception handling kicks in.

再次提醒氓仲,在處理響應(yīng)期間水慨,中間件的執(zhí)行順序是倒序執(zhí)行的,這包括process_exception敬扛。如果一個(gè)異常處理的中間件返回了一個(gè)響應(yīng)晰洒,那這個(gè)中間件上面的中間件都將不會(huì)被調(diào)用。

__init__

大多數(shù)的中間件類都不需要一個(gè)初始化方法啥箭,因?yàn)橹虚g件的類定義僅僅是為process_*提供一個(gè)占位符谍珊。如果你確實(shí)需要一個(gè)全局的狀態(tài)那就可以通過(guò)__init__來(lái)加載。然后要銘記如下兩個(gè)警告:

Django初始化你的中間件無(wú)需任何參數(shù)急侥,因此不要定義一個(gè)有參數(shù)的__init__方法砌滞。
不像process_*每次請(qǐng)求到達(dá)都要調(diào)用__init__只會(huì)被調(diào)用一次,就是在Web服務(wù)啟動(dòng)的時(shí)候坏怪。

標(biāo)記中間件不被使用

有時(shí)在運(yùn)行時(shí)決定是否一個(gè)中間件需要被加載是很有用的贝润。 在這種情況下,你的中間件中的 __init__方法可以拋出一個(gè)django.core.exceptions.MiddlewareNotUsed異常铝宵。Django會(huì)從中間件處理過(guò)程中移除這部分中間件打掘,并且當(dāng)DEBUG為True的時(shí)候在django.request記錄器中記錄調(diào)試信息。

1.8中的修改:

之前 MiddlewareNotUsed異常不會(huì)被記錄鹏秋。

指導(dǎo)準(zhǔn)則

  • 中間件的類不能是任何類的子類尊蚁。
  • 中間件可以存在與你Python路徑中的任何位置。 Django所關(guān)心的只是被包含在MIDDLEWARE_CLASSES中的配置侣夷。
  • 將Django’s available middleware作為例子隨便看看横朋。
  • 如果你認(rèn)為你寫的中間件組建可能會(huì)對(duì)其他人有用,那就把它共享到社區(qū)百拓! 讓我們知道它琴锭,我們會(huì)考慮把它添加到Django中晰甚。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市祠够,隨后出現(xiàn)的幾起案子压汪,更是在濱河造成了極大的恐慌粪牲,老刑警劉巖古瓤,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異腺阳,居然都是意外死亡落君,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門亭引,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)绎速,“玉大人,你說(shuō)我怎么就攤上這事焙蚓∥圃” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵购公,是天一觀的道長(zhǎng)萌京。 經(jīng)常有香客問(wèn)我,道長(zhǎng)宏浩,這世上最難降的妖魔是什么知残? 我笑而不...
    開封第一講書人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮比庄,結(jié)果婚禮上求妹,老公的妹妹穿的比我還像新娘。我一直安慰自己佳窑,他們只是感情好制恍,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著神凑,像睡著了一般净神。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上耙厚,一...
    開封第一講書人閱讀 52,255評(píng)論 1 308
  • 那天强挫,我揣著相機(jī)與錄音,去河邊找鬼薛躬。 笑死俯渤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的型宝。 我是一名探鬼主播八匠,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼絮爷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了梨树?” 一聲冷哼從身側(cè)響起坑夯,我...
    開封第一講書人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抡四,沒想到半個(gè)月后柜蜈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡指巡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年淑履,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藻雪。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡秘噪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出勉耀,到底是詐尸還是另有隱情指煎,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布便斥,位于F島的核電站至壤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏椭住。R本人自食惡果不足惜崇渗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望京郑。 院中可真熱鬧宅广,春花似錦、人聲如沸些举。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)户魏。三九已至驶臊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叼丑,已是汗流浹背关翎。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鸠信,地道東北人纵寝。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像星立,于是被迫代替她去往敵國(guó)和親爽茴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子葬凳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容