Django 之 中間件
一、概念
1、什麽是中間件?
官方解釋:中間件是用來處理Django的請求和響應的框架級別的鉤子。基於全局範圍產生影響。
平民解釋:中間件是幫助我們在視圖函數執行前和執行後做的操作。它本質上就是一個自定義類,類中定義了幾個方法,Django框架會在處理請求的特定的時間去執行這些方法。其余request請求,終於response請求。
2、中間件在Django項目中Settings.py文件的配置
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‘, ]
MIDDLEWARE配置項是一個列表,列表中是一個個字符串,這些字符串其實是一個一個的類,也就是一個一個的中間件。
3、自定義中間件
1、中間件可以定義五個方法,分別是:
1、process_request(self,request) 處理請求的方法
2、process_view(self,request,view_func,view_args,view_kwargs) 處理視圖的方法
3、process_template_response(self,request,response) 處理模板的方法
4、process_exception(self,request,exception) 處理異常的方法
5、process_response(self,request,response) 處理響應的方法
以上方法的返回值可以使None,或者是HttpResponse對象,如果是None,就按照自定義的中間件的方法繼續向下執行,直到process_response方法執行結束,如果是HttpResponse對象,就直接將這個對象返回給用戶。
二、五種自定義中間件
1、process_request
自定義一個中間件的示例
1、在APP下創建一個py文件,在py文件中定義中間件
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): # process_request方法 print("MD1裏面的 process_request") # 此時沒有返回值 依次向下執行 def process_response(self, request, response): # process_response方法 print("MD1裏面的 process_response") return response
class MD2(MiddlewareMixin):
def process_request(self, request): # process_request方法
print("MD2裏面的 process_request") # 此時沒有返回值 依次向下執行
def process_response(self, request, response): # process_response方法
print("MD2裏面的 process_response")
return response
2、需要在setting.py中的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‘, ‘middlewares.MD1‘, # 自定義中間件MD1 ‘middlewares.MD2‘ # 自定義中間件MD2 ]
3、當瀏覽器發送了請求之後,Django服務器響應請求,返回給瀏覽器。此時終端打印出如下內容:
MD1裏面的 process_request
MD2裏面的 process_request
app01 中的 index視圖
4、如果把MD1he MD2在setting.py中的順序調換一下,打印內容就是如下:
MD2裏面的 process_request
MD1裏面的 process_request
app01 中的 index視圖
因此,process_request的執行順序是按照註冊順序執行的。且是在視圖函數執行前執行的。
5、總結:
1、中間件的process_request方法是在執行視圖函數之前執行的。
2、當配置多個中間件時,會按照MIDDLEWARE中的註冊順序,從上到下依次執行。
3、不同中間件之間傳遞的request都是同一個對象。從請求開始到響應結束,request都是同一個對象。
4、如果內部有返回 HttpResponse對象,則不去執行視圖函數,而是直接跳過所有的中間環節,執行process_response方法,以及其前邊的方法。
2、process_response
1、示例
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): # 中間件MD1 def process_request(self, request): # process_response方法 print("MD1裏面的 process_request") def process_response(self, request, response): print("MD1裏面的 process_response") return response class MD2(MiddlewareMixin): # 中間件MD2 def process_request(self, request): print("MD2裏面的 process_request") def process_response(self, request, response): print("MD2裏面的 process_response") return response # 每個類都是一個中間件
2、process_response(self,request,response)有兩個參數,request就是一個請求對象,response是視圖函數放給的HttpResponse對象。該方法的返回值,也就是直接在中間件中寫的返回值也必須是HttpResponse對象。
3、訪問視圖函數,即匹配URL之後,執行視圖函數。打印如下內容
MD2裏面的 process_request
MD1裏面的 process_request
app01 中的 index視圖
MD1裏面的 process_response
MD2裏面的 process_response
如圖所示:process_response方法是在視圖函數執行之後,執行的。並且當有多個process_response方法時,按照 註冊順序的倒敘執行。
3、process_view
1、處理視圖的函數
process_view(self,request,view_func,view_args,view_kwargs)
該方法有四個參數
1.request是HttpRequest對象
2.view_func 是Django使用的視圖函數。(它是實際的函數對象,而不是一個單純的函數名字)。
3.view_args是傳遞給視圖函數的位置參數的元祖
4.view_kwargs是傳遞給視圖函數的關鍵字參數的字典
2、Django會在調用視圖函數前調用process_view方法。
他可以返回None或HttpResponse對象。如果返回None,繼續向下執行,如果返回HttpResponse對象,將不再繼續向下執行其他中間件中的process_view方法,而是直接執行process_response方法。
3、示例
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): # resquest 方法 print("MD1裏面的 process_request") def process_response(self, request, response): # response 方法 print("MD1裏面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): # view方法 print("-" * 80) print("MD1 中的process_view") print(view_func, view_func.__name__) 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__)
輸出結果
MD2裏面的 process_request MD1裏面的 process_request -------------------------------------------------------------------------------- MD2 中的process_view <function index at 0x000001DE68317488> index -------------------------------------------------------------------------------- MD1 中的process_view <function index at 0x000001DE68317488> index app01 中的 index視圖 MD1裏面的 process_response MD2裏面的 process_response
由圖可知:process_view方法是在process_request之後,視圖函數之前,並且按照註冊順序的正序執行。
4、process_exception
1、處理異常的方法
2、參數
process_exception(self,request,exception)
1、HttpRequest對象
2、視圖函數異常時產生的Exception對象
3、只有當視圖函數異常時才會執行。如果返回只是None,就繼續向下執行,如果返回值是一個HttpResponse對象,則不再繼續向下執行其他的中間件的process_exception方法,而是直接執行process_response方法。且如果有多個中間件的時候,按照註冊順序的倒敘執行。
4、示例
from django.utils.deprecation import MiddlewareMixin 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") 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")
打印結果
MD2裏面的 process_request MD1裏面的 process_request -------------------------------------------------------------------------------- MD2 中的process_view <function index at 0x0000022C09727488> index -------------------------------------------------------------------------------- MD1 中的process_view <function index at 0x0000022C09727488> index app01 中的 index視圖 呵呵 MD1 中的process_exception MD1裏面的 process_response MD2裏面的 process_response
註意,這裏沒有執行MD2中的process_exception方法,因為MD1中的process_exception方法已經返回了響應對象。
5、process_template_response
1、參數:
process_template_response(self,request,response)
一個是HttpRequest對象,response是一個TemplateResponse對象。
2、process_template_response是在視圖函數執行完成之後立即執行的,但是前提條件是,視圖函數返回的對象有一個render()方法
3、示例
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
4、輸出結果
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方法。
Django 之 中間件