在Django中,中間件(middleware)其實就是一個類,在請求到來和結束後,Django會根據本身的規則在合適的時機執行中間件中相應的方法。python
注意:若是在其中任意中間件中request方法return了值,就會執行當前中間件的response方法,返回給用戶,而後拋出錯誤,不會再執行下一個中間件。
web
Django 1.9版本以前,若是在request方法中遇到return,會執行最後一箇中間件的response方法,而後依次回傳。django
中間件種能夠定義5個方法,分別是:緩存
1.process_request(self, request),process_response(self, request, response)
當用戶發起請求的時候會依次通過全部的中間件,這個時候的請求是process_request,最後到達views函數中,views函數處理後,再依次穿過中間件,這個時候是process_response,最後返回給請求者,在Django中叫作中間件,在其餘web框架中,有的叫管道或httphandle
session
上述截圖中的中間件都是Django中的,咱們也能夠定義本身的中間件,本身寫一個類(可是必須繼承MiddlewareMixin),下文會對自定義中間件進行詳細介紹。app
2.process_view(self, request, callback, callback_args, callback_kwargs)框架
練習 1函數
from django.utils.deprecation import MiddlewareMixin class M1(MiddlewareMixin): def process_request(self, request): print("M1.request") def process_view(self, request, callback, callback_args, callback_kwargs): print("M1.process_view") def process_response(self, request, response): print("M1.response") return response class M2(MiddlewareMixin): def process_request(self, request): print("M2.request") def process_view(self, request, callback, callback_args, callback_kwargs): print("M2.process_view") def process_response(self, request, response): print("M2.response") return response
執行結果爲:
組件化
練習 2
既然process_view拿到視圖函數的名稱、參數(不執行),再執行process_view()方法,最後纔去執行視圖函數。那麼在執行process_view環節,能夠直接把函數執行返回嗎?url
from django.utils.deprecation import MiddlewareMixin class M1(MiddlewareMixin): def process_request(self, request): print("M1.request") # callback視圖函數名稱,callback_args,callback_kwargs視圖函數執行所須要的參數 def process_view(self, request, callback, callback_args, callback_kwargs): print("M1.process_view") response = callback(request, *callback_args, **callback_kwargs) return response def process_response(self, request, response): print("M1.response") return response class M2(MiddlewareMixin): def process_request(self, request): print("M2.request") def process_view(self, request, callback, callback_args, callback_kwargs): print("M2.process_view") def process_response(self, request, response): print("M2.response") return response
執行結果爲:
結論:若是process_view函數有返回值,跳轉到最後一箇中間件,執行最後一箇中間件的response方法,逐步返回。和process_request方法不同,request方法在當前中間件的response方法返回。其過程分析圖以下:
3.process_exception(self, request, exception)
from django.utils.deprecation import MiddlewareMixin class M1(MiddlewareMixin): def process_request(self, request): print("M1.request") # callback視圖函數名稱,callback_args,callback_kwargs視圖函數執行所須要的參數 def process_view(self, request, callback, callback_args, callback_kwargs): print("M1.process_view") # response = callback(request, *callback_args, **callback_kwargs) # return response def process_response(self, request, response): print("M1.response") return response def process_exception(self, request, exception): print("M1.exception") class M2(MiddlewareMixin): def process_request(self, request): print("M2.request") def process_view(self, request, callback, callback_args, callback_kwargs): print("M2.process_view") def process_response(self, request, response): print("M2.response") return response def process_exception(self, request, exception): print("M2.exception")
process_exception默認不執行,因此添加process_exception方法,啥也沒執行
process_exception方法只有在視圖函數執行出錯的時候纔會執行
M1.request M2.request M1.process_view M2.process_view 執行index M2的process_exception M1的process_exception Internal Server Error: /index/ Traceback (most recent call last): File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\handlers\exception.py", line 41, in inner response = get_response(request) File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\handlers\base.py", line 187, in _get_response response = self.process_exception_by_middleware(e, request) File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\handlers\base.py", line 185, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "F:\untitled1\app01\views.py", line 7, in index int("ok") ValueError: invalid literal for int() with base 10: 'ok' M2.response M1.response [02/Jul/2018 16:43:59] "GET /index/ HTTP/1.1" 500 62663
1.執行完全部request方法;
2.執行全部process_view方法;
3.若是視圖函數出錯,執行process_exception(最終response,process_exception的return值),若是process_exception方法有了返回值就再也不執行其餘中間件的process_exception,直接執行response方法響應;
4.執行全部response方法;
5.最後返回process_exception的返回值;
process_exception應用:在視圖函數執行出錯時,返回錯誤信息。這樣頁面就不會報錯了:
from django.utils.deprecation import MiddlewareMixin from django.http import HttpResponse class M1(MiddlewareMixin): def process_request(self, request): print("M1.request") # callback視圖函數名稱,callback_args,callback_kwargs視圖函數執行所須要的參數 def process_view(self, request, callback, callback_args, callback_kwargs): print("M1.process_view") # response = callback(request, *callback_args, **callback_kwargs) # return response def process_response(self, request, response): print("M1.response") return response def process_exception(self, request, exception): print("M1.exception") class M2(MiddlewareMixin): def process_request(self, request): print("M2.request") def process_view(self, request, callback, callback_args, callback_kwargs): print("M2.process_view") def process_response(self, request, response): print("M2.response") return response def process_exception(self, request, exception): print("M2.exception") return HttpResponse("出錯了!!")
其過程分析以下圖所示:
4.process_template_response(self, request, response)
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class M1(MiddlewareMixin): def process_request(self, request): print("M1.request") # callback視圖函數名稱,callback_args,callback_kwargs視圖函數執行所須要的參數 def process_view(self, request, callback, callback_args, callback_kwargs): print("M1.process_view") # response = callback(request, *callback_args, **callback_kwargs) # return response def process_response(self, request, response): print("M1.response") return response def process_exception(self, request, exception): print("M1.exception") class M2(MiddlewareMixin): def process_request(self, request): print("M2.request") def process_view(self, request, callback, callback_args, callback_kwargs): print("M2.process_view") def process_response(self, request, response): print("M2.response") return response def process_exception(self, request, exception): print("M2.exception") return HttpResponse("出錯了!!") def process_template_response(self, request, response): print("M2.process_template_response") return response
process_template_response方法默認不執行
process_template_response方法特性:只有在試圖函數的返回對象中有render方法纔會執行,並把對象的render方法的返回值返回給用戶(注意:不返回試圖函數的return結果了,而是返回視圖函數return值(對象)的render方法)
class M2(MiddlewareMixin): def process_request(self, request): print("M2.request") def process_view(self, request, callback, callback_args, callback_kwargs): print("M2.process_view") def process_response(self, request, response): print("M2.response") return response def process_exception(self, request, exception): print("M2.exception") return HttpResponse("出錯了!!") def process_template_response(self, request, response): # 若是試圖函數中的返回值中有render方法,纔會執行process_template_response print("M2.process_template_response") return response
視圖函數(views.py)
from django.shortcuts import render,HttpResponse # Create your views here. class Foo(): def __init__(self,requ): self.req=requ def render(self): return HttpResponse('OKKKK') def index(request): print("執行index") obj=Foo(request) return obj
執行結果爲:
應用:
既然process_template_response不返回視圖函數的return的結果,而是返回視圖函數return(對象)的render方法(多加了一個環節)。就能夠在這個視圖函數返回對象的render方法裏,作返回值的二次加工。多加工幾個,視圖函數就能夠隨便使用了(比如噴霧器有了多個噴頭,換不一樣的噴頭出不一樣的水,返回值就能夠組件化了)
from django.shortcuts import render,HttpResponse # Create your views here. class Dict(): #對視圖函數返回值作二次封裝 !! def __init__(self,requ,msg): self.req=requ self.msg=msg def render(self): a=self.msg #在render方法裏面 把視圖函數的 返回值 製做成字典 、列表等。。。 # 若是新增了其餘 一個視圖函數直接,return對象 便可!不用每一個視圖函數都寫 製做字典 列表 拼接的邏輯了 return HttpResponse(a) # def index(request): print("執行index") obj=Dict(request,"vv") return obj
1.在項目文件下建立Middle文件夾,並在該文件夾下面建立custom_middle.py文件,該文件代碼以下:
from django.utils.deprecation import MiddlewareMixin class Middle1(MiddlewareMixin): def process_request(self,request): print("來了") def process_response(self, request,response): print('走了')
2.在settings.py文件中,註冊該中間件(Django項目中的settings模塊中,有一個MIDDLEWARE_CLASSES變量,其中每一個元素都是一箇中間件)
執行結果爲
爲何結果報錯了??這是由於自定義的中間件response方法沒有return,交給下一個中間件,致使http請求中斷了!注意:自定義的中間件request方法不要return,由於返回值中間件再也不往下執行,致使http請求到達不了視圖層,由於request在視圖以前執行。
from django.utils.deprecation import MiddlewareMixin class Middle1(MiddlewareMixin): def process_request(self,request): print("來了") # 不用return Django內部自動幫咱們傳遞 def process_response(self, request,response): print('走了') return response # 執行完了這個中間件必定要 傳遞給下一個中間件
**執行結果爲
因爲中間件工做在視圖函數執行前、執行後(就像全部視圖函數的裝飾器),適合全部的請求/一部分請求作批處理,其應用主要有: