中間件

<li>中間件是一個鉤子框架,它們可以介入Django 的請求和響應(yīng)處理過程。它是一個輕量級、底層的“插件”系統(tǒng),用于在全局修改Django 的輸入或輸出。
<li>每個中間件組件負(fù)責(zé)完成某個特定的功能。例如,Django 包含的一個中間件組件AuthenticationMiddleware,它使用會話將用戶和請求關(guān)聯(lián)起來。
<li>這篇文檔講解中間件如何工作、如何激活中間件以及如何編寫你自己的中間件。Django集成了一些內(nèi)置的中間件可以直接開箱即用。

在1.10中的變化
jango 1.10 版本 更名為 MIDDLEWARE(單復(fù)同形)。

激活中間件

要激活一個中間件組件,需要把它添加到Django 配置文件中MIDDLEWARE_CLASSES(新版是MIDDLEWARE中)

<pre>
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
</pre>
Django的程序中,中間件不是必需的 —— 只要你喜歡,MIDDLEWARE可以為空 —— 但是強(qiáng)烈推薦你至少使用CommonMiddleware 元組中.
MIDDLEWARE中的順序非常重要,因為一個中間件可能依賴于另外一個。例如,AuthenticationMiddleware在會話中儲存已認(rèn)證的用戶。所以它必須在SessionMiddleware之后運行。

image.png

老版本中在請求階段中,調(diào)用視圖之前,Django會按照MIDDLEWARE_CLASSES中定義的順序自頂向下應(yīng)用中間件。
會用到兩個鉤子:
process_request()
process_view()
在響應(yīng)階段中,調(diào)用視圖之后,中間件會按照相反的順序應(yīng)用,自底向上。會用到三個鉤子:
process_exception()(僅當(dāng)視圖拋出異常的時候)
process_template_response()(僅用于模板響應(yīng))
process_response()。

編寫自己的中間件

老版本

編寫自己的中間件很容易的。每個中間件組件是一個獨立的Python 類,你可以定義上面這些方法中的一個或多個。
<li>process_request
process_request(request)
request是一個HttpRequest對象。在Django決定執(zhí)行哪個視圖之前,process_request()會在每個請求上調(diào)用。它應(yīng)該返回一個None或一個HttpResponse對象。如果返回None,Django會繼續(xù)處理這個請求,執(zhí)行其它process_request()中間件,然后process_view()中間件,最后是對應(yīng)的視圖。如果它返回一個HttpResponse對象,Django 就不用再去調(diào)用其它的request、view 或exception 中間件,或?qū)?yīng)的視圖;它將對HttpResponse 運用響應(yīng)階段的中間件,并返回結(jié)果。
<li>process_view
process_view(request, view_func, view_args, view_kwargs)

request
是一個HttpRequest對象。view_func是 Django會調(diào)用的一個Python的函數(shù)。(它是一個真實的函數(shù)對象,不是函數(shù)的字符名稱。) view_args是一個會被傳遞到視圖的位置參數(shù)列表,而view_kwargs是一個會被傳遞到視圖的關(guān)鍵字參數(shù)字典。view_args和 view_kwargs都不包括第一個視圖參數(shù)(request)。
process_view()會在Django 調(diào)用視圖之前被調(diào)用。
它將返回None或一[HttpResponse對象。如果返回None,Django 將會繼續(xù)處理這個請求,執(zhí)行其它的process_view()中間件,然后調(diào)用對應(yīng)的視圖。如果返回一個HttpResponse對象,Django 就不用再去調(diào)用其它的view 或exception 中間件,或?qū)?yīng)的視圖;它將對HttpResponse 運用響應(yīng)階段的中間件,并返回結(jié)果。

Accessing request.POST inside middleware before the view runs or in process_view() will prevent any view running after the middleware from being able to modify the upload handlers for the request, and should normally be avoided.

<li>process_exception
process_exception(request, exception)
request是一個HttpRequest對象。exception是一個被視圖中的方法拋出來的 Exception對象。
當(dāng)一個視圖拋出異常時,Django會調(diào)用process_exception()來處理。process_exception()應(yīng)該返回一個None 或者一HttpResponse
對象。如果它返回一個HttpResponse對象,模型響應(yīng)和響應(yīng)中間件會被應(yīng)用,響應(yīng)結(jié)果會返回給瀏覽器。否則, 默認(rèn)的異常處理機(jī)制將會被觸發(fā)。再次提醒,在處理響應(yīng)期間,中間件的執(zhí)行順序是倒序執(zhí)行的,這包括process_exception。如果一個異常處理的中間件返回了一個響應(yīng),那這個中間件上面的中間件都將不會被調(diào)用。

<li>process_template_response
process_template_response(request, response)
request是一個HttpRequest對象。response是一TemplateResponse對象(或等價的對象),由Django視圖或者中間件返回。
如果響應(yīng)的實例有render()方法,process_template_response()在視圖剛好執(zhí)行完畢之后被調(diào)用,這表明了它是一個TemplateResponse對象(或等價的對象)。這個方法必須返回一個實現(xiàn)了render方法的響應(yīng)對象。它可以修改給定的response對象,通過改 response.template_name和response.context_data或者它可以創(chuàng)建一個全新的 TemplateResponse或等價的對象。你不需要顯式渲染響應(yīng) —— 一旦所有的模板響應(yīng)中間件被調(diào)用,響應(yīng)會自動被渲染。在一個響應(yīng)的處理期間,中間件以相反的順序運行,這包括process_template_response()

<li>process_response
process_response(request, response)
request是一個HttpRequest對象。
response是Django視圖或者中間件返回的HttpResponse或者StreamingHttpResponse對象。
process_response()在所有響應(yīng)返回瀏覽器之前被調(diào)用。
這個方法必須返回HttpResponse或者StreamingHttpResponse對象。它可以改變已有的response,或者創(chuàng)建并返回新的HttpResponse或StreamingHttpResponse)對象。不像 process_request()和process_view()方法,即使同一個中間件類中的process_request()和process_view()方法會因為前面的一個中間件返回HttpResponse而被跳過,process_response()方法總是會被調(diào)用。特別是,這意味著你的process_response()方法不能依賴于process_request()方法中的設(shè)置。
最后,記住在響應(yīng)階段中,中間件以相反的順序被應(yīng)用,自底向上。意思是定義在MIDDLEWARE_CLASSES最底下的類會最先被運行。

例如
<pre>
class BookMiddleware(object):
def process_request(self, request):
print ("Middleware executed")
return None

把這個加到MIDDLEWARE_CLASSES里面,則相應(yīng)每一個請求時都會輸出Middleware executed
</pre>

<pre>
class AnotherMiddleware(object):
def process_request(self, request):
print "Another middleware executed"

在把BookMiddleware和AnotherMiddleware先后加入MIDDLEWARE_CLASSES中時,輸出:
Middleware executed
Another middleware executed
</pre>

process_response
<pre>
class AnotherMiddleware(object):
def process_request(self, request):
print "Another middleware executed"

def process_response(self, request, response):
    print "AnotherMiddleware process_response executed"
    return response

class BookMiddleware(object):
def process_request(self, request):
print "Middleware executed"
print request.user
#return HttpResponse("some response")
#self._start = time.time()

def process_response(self, request, response):
    print "BookMiddleware process_response executed"
    return response

在把BookMiddleware和AnotherMiddleware先后加入MIDDLEWARE_CLASSES中時,輸出
Middleware executed
Another middleware executed
AnotherMiddleware process_response executed
BookMiddleware process_response executed
requset和response的相反的順序
</pre>

新版中
內(nèi)置的中間件都繼承自
<pre>
class MiddlewareMixin(object):
def __init__(self, get_response=None):
self.get_response = get_response
super(MiddlewareMixin, self).__init__()
def __call__(self, request):
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response

__call__ 方法會先調(diào)用 self.process_request(request),接著執(zhí)行 self.get_response(request) 然后調(diào)用 self.process_response(request, response) (如果子類中定義的話)
</pre>

自定義一個新版的中間件(不繼承MiddlewareMixin)
<pre>
class SimpleMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response
def process_request(self,request):
pass
def process_response(self,request,response):
#code
</pre>

或者直接繼承MiddlewareMixin實現(xiàn)相應(yīng)的方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,958評論 2 373

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

  • Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群:467338606網(wǎng)站:h...
    布客飛龍閱讀 784評論 0 37
  • Refer to: www.threemeal.com/blog/12/ 中間件 中間件是一個鉤子框架,它們可以介...
    蘭山小亭閱讀 16,519評論 9 165
  • Django中的中間件是一個輕量級、底層的插件系統(tǒng),可以介入Django的請求和響應(yīng)處理過程,修改Django的輸...
    mlj0503閱讀 422評論 0 0
  • 知識點 概念 使用場景 中間件如何發(fā)生作用 自定義中間件 中間件概念 中間件是嵌入 django 的 reques...
    Spareribs閱讀 2,435評論 0 6
  • django處理一個Request的過程是首先通過django 中間件,然后再通過默認(rèn)的URL方式進(jìn)行的。所以說我...
    戴維得閱讀 680評論 0 0