Django之中間件

中間件

 

中間件的概念

  • 中間件顧名思義,是介於request與response處理之間的一道處理過程,相對比較輕量級,而且在全局django

    上改變django的輸入與輸出。由於改變的是全局,因此須要謹慎實用,用很差會影響到性能。瀏覽器

  • Django的中間件的定義:session

    Middleware is` `a framework of hooks into Django’s request/response processing.app

    It’s a light, low-level 「plugin」 systemforglobally altering Django’s input or框架

    output.ide

     

    中間件是一個用來處理Django的請求和響應的框架級別的鉤子。它是一個輕量、低級別的插件系統,用於在全局範圍內改變Django的輸入和輸出。每一箇中間件組件都負責作一些特定的功能。函數

     

    鉤子:在某個位置預留了位置,沒有掛鉤子函數的話繼續執行,若是寫了鉤子函數就執行完後繼續執行。post

    應用:性能

    • 若是想修改請求,例如被傳送到view中的HttpRequest對象。 或者想修改view返回的HttpResponse對象,這些均可以經過中間件來實現。ui

    • 可能還想在view執行以前作一些操做,這種狀況就能夠用 middleware來實現。

    • 咱們可能頻繁在view使用request.user吧。 Django想在每一個view執行以前把user設置request

      的屬性,因而就用了一箇中間件來實現這個目標。因此Django提供了能夠修改request 對象的中間

      AuthenticationMiddleware

    • 中間件能夠用來幹什麼?
      •   用戶登陸
          日誌記錄
          crsf:對全部的post請求作了一個驗證
          session
          權限管理
    • 注意:
        對於全部請求的批量作處理的時候用中間件
        單獨對某幾個函數作處理的時候用裝飾器
    •  Django默認的Middleware:

      MIDDLEWARE = [
         'django.middleware.security.SecurityMiddleware',
         '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',
      ]

      每個中間件都有具體的功能

    • 使用步驟
    • 步驟:
      1、、先建一個文件夾,裏面寫一個py文件
      2、、而後開始寫類
      1.中間件就是一個類,類裏面寫幾個方法
      class M1(MiddlewareMixin):  必須繼承
          def process_request(self,request):  request:請求裏面的全部的東西
              print("m1.request_request") 
              這個方法裏面別輕易返回值,要是有返回值就再也不繼續執行後面的了,執行本身的process_response和上邊的response
              通常是無返回值的:繼續執行後續的中間件和視圖函數
          def process_response(self,request,response):
              return response
          
      2.在settings中的MIDDLEWARE加上路徑    
          文件夾名稱.py文件名稱.類名
      3.找到繼承的那個類,吧那個類拿過來
        通常不要用導入的方法,否則有時候更新了就沒有這個類了,你就把它繼承的那個類拿過來,
      中間件使用步驟

 

自定義中間件

  • 中間件能夠定義五個方法,分別是:(主要的是process_request和process_response)

    • process_request(self,request)
    • process_view(self, request, view_func, view_args, view_kwargs)
    • process_template_response(self,request,response)
    • process_exception(self, request, exception)
    • process_response(self, request, response)

    以上方法的返回值能夠是None或一個HttpResponse對象,

    • 若是是None,則繼續按照django定義的規則向後繼續執行,

    • 若是是HttpResponse對象,則直接將該對象返回給用戶。

      • 總結:
      • 五個方法
        
        - 參數,執行時間,執行順序
        - 1、process_request(self, request)
          - 執行時間:在視圖函數執行以前
          - 參數:
            - request:視圖函數用到中用到的request
          - 執行順序:按照註冊順序執行
          - 返回值:
            - None:正常流程
            - HttpResponse對象:當前中間件後面的中間件的process_request方法
              process_Response方法和視圖的Http_Response對象不執行,執行當前
              中間件的process_Response方法以及以前的process_reques方法
        - 2、process_response(self, request, response)
          - 執行時間:在視圖函數執行以後
          - 參數:
            - request:視圖函數用到中用到的request
            - response:視圖函數中返回的response對象,若是中間件返回response對象,就不走
              視圖函數了
          - 執行順序:按照註冊順序倒序執行
          - 返回值:
            - 不能爲None,不然會報錯
            - 必須是response對象
        - 3、process_view(self, request, view_func, view_args, view_kwargs)
          - 執行時間:在視圖函數以前,在process_reques方法以後,以及路由匹配以後
          - 參數:
            - request:視圖函數用到中用到的request
            - view_func:要執行的視圖函數
            - view_args:視圖函數的位置參數
            - view_kwargs:視圖函數的關鍵字參數
          - 返回值:
            - None:正常流程
            - HttpResponse對象:
          - 執行屬性:按照註冊順序執行
        - 4、process_exception(self, request, exception)
          - 執行時間:
            - 觸發條件:有異常才執行
            - 在視圖函數以後,在process_response以前
          - 參數:
            - request:視圖函數用到中用到的request
            - exception:錯誤信息對象
          - 返回值:HttpResponse對象:
            - None:正常執行
            - HttpResponse對象:
              - 註冊順序以前的全部中間件的process_exception方法不走了
              - 執行全部中間件的的process_response
          - 執行順序:按照註冊順序倒序執行
        - 5、process_template_response(self, request, response)
          - 執行時間:
            - 觸發條件:返回的response對象要有一個render方法
            - 在視圖函數以後,在process_response方法以前
          - 參數「
            - request:視圖函數用到中用到的request
            - response:視圖函數中返回的response對象
          - 返回值:
            - 不能爲None,不然會報錯
            - 必須是response對象
          - 執行順序:按照註冊順序倒序執行(不會截斷,可以重寫)
        五個方法總結
        - process_request(self,request)
            1、中間件的process_request方法是在執行視圖函數以前執行的。
            2、當配置多箇中間件時,會按照MIDDLEWARE中的註冊順序,也就是列表的索引值,從前到後依次執行的。
            3、不一樣中間件之間傳遞的request都是同一個對象
        
        
        - process_response(self, request, response)
            1、process_response方法是在視圖函數以後執行的,而且順序是MD1比MD2先執行。(此時settings.py中 MD2比MD1先註冊)
            2、多箇中間件中的process_response方法是按照MIDDLEWARE中的註冊順序倒序執行的,也就是說第一個中間件的process_request方法首先執行,而它的process_response方法最後執行,最後一箇中間件的process_request方法最後一個執行,它的process_response方法是最早執行。
        
        
        - process_view(self, request, view_func, view_args, view_kwargs)
            1、Django會在調用視圖函數以前調用process_view方法。
            2、它應該返回None或一個HttpResponse對象。 若是返回None,Django將繼續處理這個請求,執行任何其餘中間件的process_view方法,而後在執行相應的視圖。 若是它返回一個HttpResponse對象,Django不會調用適當的視圖函數。 它將執行中間件的process_response方法並將應用到該HttpResponse並返回結果。
            3、process_view方法是在process_request以後,視圖函數以前執行的,執行順序按照MIDDLEWARE中的註冊順序從前到後順序執行的。
          
        
        - process_exception(self, request, exception)
            1、這個方法只有在視圖函數中出現異常了才執行,它返回的值能夠是一個None也能夠是一個HttpResponse對象。若是是HttpResponse對象,Django將調用模板和中間件中的process_response方法,並返回給瀏覽器,不然將默認處理異常。若是返回一個None,則交給下一個中間件的process_exception方法來處理異常。它的執行順序也是按照中間件註冊順序的倒序執行。
        
        
        - process_template_response(self,request,response)
            1、process_template_response是在視圖函數執行完成後當即執行,可是它有一個前提條件,那就是視圖函數返回的對象有一個render()方法(或者代表該對象是一個TemplateResponse對象或等價方法)。
            二、視圖函數執行完以後,當即執行了中間件的process_template_response方法,順序是倒序,先執行MD1的,在執行MD2的,接着執行了視圖函數返回的HttpResponse對象的render方法,返回了一個新的HttpResponse對象,接着執行中間件的process_response方法。

         

    •  

      process_request,process_response
      • 當用戶發起請求的時候會依次通過全部的的中間件,這個時候的請求時process_request,最後到達views的函數中,views函數處理後,在依次穿過中間件,這個時候是process_response,最後返回給請求者。

      • 咱們也能夠本身定義一箇中間件,咱們能夠本身寫一個類,可是必須繼承MiddlewareMixin

        須要導入

        from django.utils.deprecation import MiddlewareMixin
      • in views:

        def index(request):

           print("view函數...")
           return HttpResponse("OK")

        in Mymiddlewares.py:

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

        class Md1(MiddlewareMixin):

           def process_request(self,request):
               print("Md1請求")

           def process_response(self,request,response):
               print("Md1返回")
               return response

        class Md2(MiddlewareMixin):

           def process_request(self,request):
               print("Md2請求")
               #return HttpResponse("Md2中斷")
           def process_response(self,request,response):
               print("Md2返回")
               return response

        結果:

        Md1請求
        Md2請求
        view函數...
        Md2返回
        Md1返回

        注意:若是當請求到達請求2的時候直接不符合條件返回,即return HttpResponse("Md2中斷"),程序將把請求直接發給中間件2返回,而後依次返回到請求者,結果以下:

        返回Md2中斷的頁面,後臺打印以下:

        Md1請求
        Md2請求
        Md2返回
        Md1返回

        流程圖以下:

      process_view
      process_view(self, request, callback, callback_args, callback_kwargs)

      Mymiddlewares.py修改以下

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

      class Md1(MiddlewareMixin):

         def process_request(self,request):
             print("Md1請求")
             #return HttpResponse("Md1中斷")
         def process_response(self,request,response):
             print("Md1返回")
             return response

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

      class Md2(MiddlewareMixin):

         def process_request(self,request):
             print("Md2請求")
             return HttpResponse("Md2中斷")
         def process_response(self,request,response):
             print("Md2返回")
             return response

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

      結果以下:

      Md1請求
      Md2請求
      Md1view
      Md2view
      view函數...
      Md2返回
      Md1返回

      下圖進行分析上面的過程:

      當最後一箇中間的process_request到達路由關係映射以後,返回到中間件1的process_view,而後

      依次往下,到達views函數,最後經過process_response依次返回到達用戶。

      process_view能夠用來調用視圖函數:

      class Md1(MiddlewareMixin):

         def process_request(self,request):
             print("Md1請求")
             #return HttpResponse("Md1中斷")
         def process_response(self,request,response):
             print("Md1返回")
             return response

         def process_view(self, request, callback, callback_args, callback_kwargs):

             # return HttpResponse("hello")

             response=callback(request,*callback_args,**callback_kwargs)
             return response

      結果以下:

      Md1請求
      Md2請求
      view函數...
      Md2返回
      Md1返回

      注意:process_view若是有返回值,會越過其餘的process_view以及視圖函數,可是全部的

      process_response都還會執行。

      process_exception
      process_exception(self, request, exception)

      示例修改以下:

      class Md1(MiddlewareMixin):

         def process_request(self,request):
             print("Md1請求")
             #return HttpResponse("Md1中斷")
         def process_response(self,request,response):
             print("Md1返回")
             return response

         def process_view(self, request, callback, callback_args, callback_kwargs):

             # return HttpResponse("hello")

             # response=callback(request,*callback_args,**callback_kwargs)
             # return response
             print("md1 process_view...")

         def process_exception(self):
             print("md1 process_exception...")



      class Md2(MiddlewareMixin):

         def process_request(self,request):
             print("Md2請求")
             # return HttpResponse("Md2中斷")
         def process_response(self,request,response):
             print("Md2返回")
             return response
         def process_view(self, request, callback, callback_args, callback_kwargs):
             print("md2 process_view...")

         def process_exception(self):
             print("md1 process_exception...")

      結果以下:

      Md1請求
      Md2請求
      md1 process_view...
      md2 process_view...
      view函數...

      Md2返回
      Md1返回

      流程圖以下:

      當views出現錯誤時:

      將md2的process_exception修改以下:

        def process_exception(self,request,exception):

             print("md2 process_exception...")
             return HttpResponse("error")

      結果以下:

      Md1請求
      Md2請求
      md1 process_view...
      md2 process_view...
      view函數...
      md2 process_exception...
      Md2返回
      Md1返回
    • process_template_response(用的比較少)

        process_template_response(self, request, response)

            它的參數,一個HttpRequest對象,response是TemplateResponse對象(由視圖函數或者中間件產生)。

           process_template_response是在視圖函數執行完成後當即執行,可是它有一個前提條件,那就是視圖函數返回的對象有一個render()方法(或者代表該對象是一個TemplateResponse對象或等價方法)。

      複製代碼
      class MD1(MiddlewareMixin):
      
          def process_request(self, request):
              print("MD1裏面的 process_request")
      
          def process_response(self, request, response):
              print("MD1裏面的 process_response")
              return response
      
          def process_view(self, request, view_func, view_args, view_kwargs):
              print("-" * 80)
              print("MD1 中的process_view")
              print(view_func, view_func.__name__)
      
          def process_exception(self, request, exception):
              print(exception)
              print("MD1 中的process_exception")
              return HttpResponse(str(exception))
      
          def process_template_response(self, request, response):
              print("MD1 中的process_template_response")
              return response
      
      
      class MD2(MiddlewareMixin):
          def process_request(self, request):
              print("MD2裏面的 process_request")
      
          def process_response(self, request, response):
              print("MD2裏面的 process_response")
              return response
      
          def process_view(self, request, view_func, view_args, view_kwargs):
              print("-" * 80)
              print("MD2 中的process_view")
              print(view_func, view_func.__name__)
      
          def process_exception(self, request, exception):
              print(exception)
              print("MD2 中的process_exception")
      
          def process_template_response(self, request, response):
              print("MD2 中的process_template_response")
              return response
      複製代碼

      views.py中:

      複製代碼
      def index(request):
          print("app01 中的 index視圖")
      
          def render():
              print("in index/render")
              return HttpResponse("O98K")
          rep = HttpResponse("OK")
          rep.render = render
          return rep
      複製代碼

      訪問index視圖,終端輸出的結果:

      複製代碼
      MD2裏面的 process_request
      MD1裏面的 process_request
      --------------------------------------------------------------------------------
      MD2 中的process_view
      <function index at 0x000001C111B97488> index
      --------------------------------------------------------------------------------
      MD1 中的process_view
      <function index at 0x000001C111B97488> index
      app01 中的 index視圖
      MD1 中的process_template_response
      MD2 中的process_template_response
      in index/render
      MD1裏面的 process_response
      MD2裏面的 process_response
      複製代碼

      從結果看出:

      視圖函數執行完以後,當即執行了中間件的process_template_response方法,順序是倒序,先執行MD1的,在執行MD2的,接着執行了視圖函數返回的HttpResponse對象的render方法,返回了一個新的HttpResponse對象,接着執行中間件的process_response方法。

相關文章
相關標籤/搜索