Django - 中間件
2. 今日內容 https://www.cnblogs.com/liwenzhou/p/8761803.html https://www.cnblogs.com/liwenzhou/p/8761803.html HTTP: 請求格式: HTTP/1.1 /index GET \r\n k1:v1 \r\n ... 請求體 響應格式 HTTP/1.1 200 OK K1:V1 \r\n Content-Type:‘text/html;charset=utf-8 \r\n ... 響應體 圖筆記------- 圖------------ 由此總結一下: 中間件的process_request方法是在執行視圖函數之前執行的。 當配置多個中間件時,會按照MIDDLEWARE中的註冊順序,也就是列表的索引值,從前到後依次執行的。 不同中間件之間傳遞的request都是同一個對象 0. Django的請求流程圖 importlib 模塊 1.中間件(酌情使用!!!) 每個請求都要過中間件 多了 慢 學習的關鍵就是: 五個相關方法,在請求生命周期的何時按照何種順序執行!!!!!1. process_request(self, request) - 視圖函數執行之前(在urls.py找對應關系之前) - 註冊順序 2. process_response(self, request, response) - 視圖函數執行之後 - 註冊順序的倒序 3. process_view(self, view_func, view_args, view_kwargs)- 視圖函數執行之前(在urls.py中找到對應關系之後) 此時view_func就是將要執行的視圖函數對象!!! - 註冊順序 4. process_exception(self, request, exception) - 視圖函數執行之後,只有在有異常的時候才執行 - 註冊順序的倒序 5. process_template_response(self, request, response) (csrf-token就是在這個中間件裏面寫的) - 視圖函數執行之後,只有在響應對象有render方法的時候才執行 - 註冊順序的倒序 m1.process_request return none ...往下走 return response 不走後面了 m2.process_request url m1.process_view m2.process_view view orm / template m2.process_exception return response // 有異常才會調用 raise ValueError(‘hehe,拋異常‘) m1.process_exception m2.process_template_response return response // 返回對象有render方法時 才會調用 m1.process_template_response m2.process_response m1.process_response 兩張 圖------- 2. Django項目logging模塊的配置和使用 https://www.cnblogs.com/liwenzhou/p/8763264.html 3. 作業 1. 中間件版的登錄校驗(博客有答案,自己寫完再看) 2. 自己去查資料學習下importlib模塊(培養自己的自學能力) 3. 祝你們幸福!
前戲:
前面的內容已經學會了給視圖函數加裝飾器來判斷是用戶是否登錄,把沒有登錄的用戶請求跳轉到登錄頁面。我們通過給幾個特定視圖函數加裝飾器實現了這個需求。但是以後添加的視圖函數可能也需要加上裝飾器,這樣是不是稍微有點繁瑣。
學完今天的內容之後呢,我們就可以用更適宜的方式來實現類似給所有請求都做相同操作的功能了。
一、中間件介紹
什麽是中間件?
官方的說法:中間件是一個用來處理Django的請求和響應的框架級別的鉤子。它是一個輕量、低級別的插件系統,用於在全局範圍內改變Django的輸入和輸出。每個中間件組件都負責做一些特定的功能。
但是由於其影響的是全局,所以需要謹慎使用,使用不當會影響性能。
說的直白一點中間件是幫助我們在視圖函數執行之前和執行之後都可以做一些額外的操作,它本質上就是一個自定義類,類中定義了幾個方法,Django框架會在請求的特定的時間去執行這些方法。
我們一直都在使用中間件,只是沒有註意到而已,打開Django項目的Settings.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‘, ]
MIDDLEWARE配置項是一個列表,列表中是一個個字符串,這些字符串其實是一個個類,也就是一個個中間件。
我們之前已經接觸過一個csrf相關的中間件了?我們一開始讓大家把他註釋掉,再提交post請求的時候,就不會被forbidden了,後來學會使用csrf_token之後就不再註釋這個中間件了。
那接下來就學習中間件中的方法以及這些方法什麽時候被執行。
二、自定義中間件
中間件可以定義五個方法,分別是:(主要的是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對象,則直接將該對象返回給用戶。
自定義一個中間件示例:
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
三、process_request
process_request有一個參數,就是request,這個request和視圖函數中的request是一樣的。
它的返回值可以是None也可以是HttpResponse對象。返回值是None的話,按正常流程繼續走,交給下一個中間件處理,如果是HttpResponse對象,Django將不執行視圖函數,而將相應對象返回給瀏覽器。
我們來看看多個中間件時,Django是如何執行其中的process_request方法的。
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("MD1裏面的 process_request") class MD2(MiddlewareMixin): def process_request(self, request): print("MD2裏面的 process_request") pass
在settings.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 ]
此時,我們訪問一個視圖,會發現終端中打印如下內容:
MD1裏面的 process_request
MD2裏面的 process_request
app01 中的 index視圖
把MD1和MD2的位置調換一下,再訪問一個視圖,會發現終端中打印的內容如下:
MD2裏面的 process_request
MD1裏面的 process_request
app01 中的 index視圖
看結果我們知道:視圖函數還是最後執行的,MD2比MD1先執行自己的process_request方法。
在打印一下兩個自定義中間件中process_request方法中的request參數,會發現它們是同一個對象。
由此總結一下:
- 中間件的process_request方法是在執行視圖函數之前執行的。
- 當配置多個中間件時,會按照MIDDLEWARE中的註冊順序,也就是列表的索引值,從前到後依次執行的。
- 不同中間件之間傳遞的request都是同一個對象
多個中間件中的process_response方法是按照MIDDLEWARE中的註冊順序倒序執行的,也就是說第一個中間件的process_request方法首先執行,而它的process_response方法最後執行,最後一個中間件的process_request方法最後一個執行,它的process_response方法是最先執行。
四、process_response
它有兩個參數,一個是request,一個是response,request就是上述例子中一樣的對象,response是視圖函數返回的HttpResponse對象。該方法的返回值也必須是HttpResponse對象。
給上述的M1和M2加上process_response方法:
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 class MD2(MiddlewareMixin): def process_request(self, request): print("MD2裏面的 process_request") pass def process_response(self, request, response): print("MD2裏面的 process_response") return response
訪問一個視圖,看一下終端的輸出:
MD2裏面的 process_request
MD1裏面的 process_request
app01 中的 index視圖
MD1裏面的 process_response
MD2裏面的 process_response
看結果可知:
process_response方法是在視圖函數之後執行的,並且順序是MD1比MD2先執行。(此時settings.py中 MD2比MD1先註冊)
多個中間件中的process_response方法是按照MIDDLEWARE中的註冊順序倒序執行的,也就是說第一個中間件的process_request方法首先執行,而它的process_response方法最後執行,最後一個中間件的process_request方法最後一個執行,它的process_response方法是最先執行。
五、process_view
process_view(self, request, view_func, view_args, view_kwargs)
該方法有四個參數
request是HttpRequest對象。
view_func是Django即將使用的視圖函數。 (它是實際的函數對象,而不是函數的名稱作為字符串。)
view_args是將傳遞給視圖的位置參數的列表.
view_kwargs是將傳遞給視圖的關鍵字參數的字典。 view_args和view_kwargs都不包含第一個視圖參數(request)。
Django會在調用視圖函數之前調用process_view方法。
它應該返回None或一個HttpResponse對象。 如果返回None,Django將繼續處理這個請求,執行任何其他中間件的process_view方法,然後在執行相應的視圖。 如果它返回一個HttpResponse對象,Django不會調用適當的視圖函數。 它將執行中間件的process_response方法並將應用到該HttpResponse並返回結果。
給MD1和MD2添加process_view方法:
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__) class MD2(MiddlewareMixin): def process_request(self, request): print("MD2裏面的 process_request") pass 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__)
訪問index視圖函數,看一下輸出結果:
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之後,視圖函數之前執行的,執行順序按照MIDDLEWARE中的註冊順序從前到後順序執行的
六、process_exception
七、process_template_response(用的比較少)
八、中間件的執行流程
Django - 中間件