Django之Middleware中間件(***)

Django之Middleware中間件(***)前端

  Middleware中間件,是在Django有HTTP請求時,在url去路由匹配以前的一道工序。是一道驗證的功能。django

  在中間件中,有兩個必有的方法。一個是接收到HTTP請求後要處理的。一個是處理完返回客戶端時通過中間件要處理的方法。後端

  中間件就是一個類,可是要想應用這個類,是須要進行在Settings中的中間件列表中註冊的。那既然是列表,那麼中間件的執行順序是有序的。函數

  這個類的兩個必要的方法:process_request 和 process_response。url

  其中process_response是有return返回值的。而process_request是沒有return返回值的。spa

  若是process_request有返回值,那麼HTTP請求就不會再進入路由匹配,而是直接在中間件就返回啦。code

  可是Django的版本不一樣,中間件也會有些許的區別:中間件

    Django1.10以後的版本:中間件的process_request有返回值,會直接用同中間件的process_response返回結果,而不是繼續執行流程,去路由匹配views。在返回給用戶應該的相應的結果。blog

    Django1.7或1.8以前的(含1.7/1.8):中間件的process_request有返回值,中間件的流程依舊會繼續執行,它會找到最後的一箇中間件,經過最後的中間件的process_response來返回,這個1.10的版本不一樣,10是同中間件的process_response直接返回,1.8以前是用最後的process_response返回。資源

 

  中間件的編寫實例:

  Settings中導入模塊並添加md的中間件:

  md.py 中間件:

from django.utils.deprecation import MiddlewareMixin

class M1(MiddlewareMixin):
    def process_request(self,request):
        print("m1.process_request")

    def process_response(self,request,response):
        print("m1.process_response")
        return response

class M2(MiddlewareMixin):
    def process_request(self, request):
        print("m2.process_request")

    def process_response(self, request, response):
        print("m2.process_response")
        return response

  函數test:

def test(request):
    print("test")
    return HttpResponse("...")

  中間件的執行順序,m1-m2-函數-m2-m1

  當md中的中間件加上process_view函數方法:

from django.utils.deprecation import MiddlewareMixin

class M1(MiddlewareMixin):
    def process_request(self,request):
        print("m1.process_request")

    def process_view(self,request,callback,callback_args,callback_kwargs):
        print("m1.process_view")

    def process_response(self,request,response):
        print("m1.process_response")
        return response

class M2(MiddlewareMixin):
    def process_request(self, request):
        print("m2.process_request")

    def process_view(self,request,callback,callback_args,callback_kwargs):
        print("m2.process_view")

    def process_response(self, request, response):
        print("m2.process_response")
        return response

 

  它的執行順序會發生變化,他會在執行test函數並返回m1和m2的process_response以前,先去執行m1和m2的process_view。

  其緣由是:

    在執行完process_request的m1和m2後,又返回到了最開始的中間件,去順序執行m1和m2的process_view。

    可是,在執行m1和m2的process_view這間,Django作了件路由匹配的事情,process_view的參數callback實際上是view_func的函數,好比咱們示例中的test,這個callback參數就是去匹配view視圖中test函數的路由關係啦。

from django.utils.deprecation import MiddlewareMixin

class M1(MiddlewareMixin):
    def process_request(self,request):
        print("m1.process_request")

    def process_view(self,request,callback,callback_args,callback_kwargs):
        print(callback,callback_args,callback_kwargs)
        print("m1.process_view")

    def process_response(self,request,response):
        print("m1.process_response")
        return response

class M2(MiddlewareMixin):
    def process_request(self, request):
        print("m2.process_request")

    def process_view(self,request,callback,callback_args,callback_kwargs):
        print("m2.process_view")

    def process_response(self, request, response):
        print("m2.process_response")
        return response

  在中間件中打印一下process_view的m1就能夠看出,在中間件執行完m2後,會再一次回到原點,去匹配對應函數的路由。

 

   因此,在中間件中加上process_view方法後,中間件的執行順序會有變化,而這中間作的事情就是去路由中匹配對應的函數。

  可是這裏發生的都是中間件中作的事情,並無觸及到真正的view函數,只有在中間件的功能的process_request都結束時,纔會真正去執行view函數。

  但奇特的是:既然在process_view中就已經完成了路由的匹配,那麼在中間件中是否是也能夠直接執行view函數吶?

  畢竟callback就是那個view的函數呀!!!!哈哈哈,好奇特。什麼鬼?

  在process_view中有兩條路能夠走,一條是繼續往下走,執行下面的process_view,還有一條路是直接返回。

from django.utils.deprecation import MiddlewareMixin

class M1(MiddlewareMixin):
    def process_request(self,request):
        print("m1.process_request")

    def process_view(self,request,callback,callback_args,callback_kwargs):
        print("m1.process_view")
        respones = callback(request,*callback_args,**callback_kwargs)
        return respones

    def process_response(self,request,response):
        print("m1.process_response")
        return response

class M2(MiddlewareMixin):
    def process_request(self, request):
        print("m2.process_request")

    def process_view(self,request,callback,callback_args,callback_kwargs):
        print("m2.process_view")

    def process_response(self, request, response):
        print("m2.process_response")
        return response

  這裏的process_view執行了m1的,並無執行m2的process_view。

 

   這裏的流程是當m2的process_view有返回值時,它是再也不執行下一個中間件的,而不是去真正的view裏執行,而是直接從最後的中間件開始返回。

 

   因此當process_view中有返回值的時候,它會執行完全部的process_response再返回。

  中間件中一共有5個方法:還有 process_template_response 和 process_exception 倆個方法。

  exception是異常相關的:

    正常狀況下,這個函數方法是不會被執行的,只有在有異常報錯的狀況下,纔會觸發這個方法。

from django.utils.deprecation import MiddlewareMixin

class M1(MiddlewareMixin):
    def process_request(self,request):
        print("m1.process_request")

    def process_view(self,request,callback,callback_args,callback_kwargs):
        print("m1.process_view")
        #respones = callback(request,*callback_args,**callback_kwargs)
        #return respones

    def process_response(self,request,response):
        print("m1.process_response")
        return response

    def process_exception(self,request,exception):
        print("m1.process_exception")

class M2(MiddlewareMixin):
    def process_request(self, request):
        print("m2.process_request")

    def process_view(self,request,callback,callback_args,callback_kwargs):
        print("m2.process_view")

    def process_response(self, request, response):
        print("m2.process_response")
        return response

    def process_exception(self,request,exception):
        print("m2.process_exception")

  這裏的view視圖的test函數中我們讓其故意出錯

def test(request):
    print("test")
    int("asfafa")
    return HttpResponse("...")

  其結果是:

    前端報錯:

    

 

   後端報錯:    

 

   他執行的順序是想執行完process_request和process_view,去view視圖處理完髮現異常後,交付的是m2和m1的process_exception。

  最後纔在回到最後的中間件m2開始執行m2和m1的process_response。

  在m2的process_execption中捕獲一下異常。

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class M1(MiddlewareMixin):
    def process_request(self,request):
        print("m1.process_request")

    def process_view(self,request,callback,callback_args,callback_kwargs):
        print("m1.process_view")
        # respones = callback(request,*callback_args,**callback_kwargs)
        # return respones

    def process_response(self,request,response):
        print("m1.process_response")
        return response

    def process_exception(self,request,exception):
        print("m1.process_exception")

class M2(MiddlewareMixin):
    def process_request(self, request):
        print("m2.process_request")

    def process_view(self,request,callback,callback_args,callback_kwargs):
        print("m2.process_view")

    def process_response(self, request, response):
        print("m2.process_response")
        return response

    def process_exception(self,request,exception):
        print("m2.process_exception")
        return HttpResponse("錯誤了。。。")

  頁面不在報錯,而是有return的返回:

 

   它的輸出的結果變成了:

 

   這裏沒有了m1的process_execption。因此,他在m2的process_execption中處理了以後,就不會在去m1的process_execption了,而是再回到m2的process_response順序處理,並返回給用戶。

  最後是process_template_response 方法的應用:

 

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class M1(MiddlewareMixin):
    def process_request(self,request):
        print("m1.process_request")

    def process_view(self,request,callback,callback_args,callback_kwargs):
        print("m1.process_view")
        # respones = callback(request,*callback_args,**callback_kwargs)
        # return respones

    def process_response(self,request,response):
        print("m1.process_response")
        return response

    def process_exception(self,request,exception):
        print("m1.process_exception")

    def process_template_response(self,request,response):
        print("m1.process_template_response")
        return response

class M2(MiddlewareMixin):
    def process_request(self, request):
        print("m2.process_request")

    def process_view(self,request,callback,callback_args,callback_kwargs):
        print("m2.process_view")

    def process_response(self, request, response):
        print("m2.process_response")
        return response

    def process_exception(self,request,exception):
        print("m2.process_exception")
        return HttpResponse("錯誤了。。。")

  結果是:

 

 這裏沒有異常的還,將再也不有process_execption,可是也沒有process_template_response。

 這裏沒有process_template_response是由於要執行這個方法是要有render的返回值。

 也就是說:process_template_response的視圖函數的返回值中,若是有render方法,纔會被調用。

  好比:視圖函數這樣寫:

class Foo:
    def __init__(self,req):
        self.req = req

    def render(self):
        return HttpResponse("...")

def test(request):
    obj = Foo(request)
    return obj

  那麼process_template_response就會被執行。由於被執行的test函數有render方法。

總結中間件:

  中間件就是一個類,這個類裏有5個方法,最爲經常使用的是process_response和process_request。

  中間件是嚴格按照順序有序的執行。

  中間件在何時會被應用到:

    當全部的請求都要統一作操做的時候,而在每一個函數裏寫是很浪費資源和時間的,因此就經過中間件的特性,當每一個請求來時都會必經的一個流程的地方作統一的處理,那就是中間件的做用,他在請求真正的去view視圖函數中處理時以前,就能夠加上咱們想要其作的事情。

    說的直白一點就是:對全部的請求或一部分請求作批量處理的。

 

----- END -----

相關文章
相關標籤/搜索