Django框架之中介軟體引入

HuangQiaoqi發表於2024-03-25

【一】中介軟體介紹

  • 之前我們透過給檢視函式加上裝飾器來判斷使用者是否登入,把沒有登陸的使用者請求跳轉到登入頁面。
  • 但是如果有很多的功能都需要在登入之後才能使用,那麼每個功能對應的檢視函式都需要加上裝飾器,這樣的話就略顯繁瑣
  • 透過django中介軟體就可以實現控制全域性的效果

【1】什麼是中介軟體

  • 官方的說法是,中介軟體是一個用於處理DJango的請求和響應的框架級別的鉤子。他是一個輕量,低階別的外掛系統,用於在全域性範圍內改變django的輸入和輸出。每個中介軟體元件都負責做一些特別的功能
  • 由於它的作用是對全域性的影響,所以需要謹慎使用,要不然會影響效能。
  • 簡單來說,中介軟體可以定義我們的檢視函式在執行之前和執行之後的一些操作,他的本質上是一個自定義類,類中定義了幾個方法,Django框架會在請求的特定時間去執行這些方法
  • django預設就有七個中介軟體,我們一直都在使用,只是沒有感覺到罷了。
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',
]

【二】自定義中介軟體

  • 最好現在應用下建立一個資料夾,資料夾下建立py檔案,py檔案內匯入MiddlewareMixin
  • 寫一個類繼承MiddlewareMixin
  • django給了我們五個可以自定義的中介軟體方法
# 可以自定義的方法
# 1.在檢視函式接收到請求之前觸發
process_request(self,request)

# 2.檢視函式被掉喲ing之前觸發
process_view(self, request, view_func, view_args, view_kwargs)

# 3.這個方法會在 Django 框架中的檢視函式返回一個 TemplateResponse 物件後執行。
process_template_response(self,request,response)

# 4.發生異常後執行
process_exception(self, request, exception)

# 5.響應資料時執行
process_response(self, request, response)

# 必須要掌握的
1.process_request(self,request)
2.process_response(self, request, response)

# 以上的方法返回值可以是None,或者是一個HttpResponse物件,如果是None,就按照原本的規則執行,
# 果如返回了HttpResponse物件,那麼直接返回一個頁面

【1】process_request

  • process_request有一個引數就是request,這個request和檢視函式里面的request物件是一樣的,在中介軟體中,在請求達到url之前,可以對這個物件做一系列操作
  • 它的返回值可以是一個None,或者是一個HttpResponse物件,如果是None,就正常走到後面的路由檢視等,如果是HttpResponse物件,那麼直接將這個物件返回到瀏覽器渲染
  • 一下是一些對中介軟體的研究

多箇中介軟體,Django是如何執行其中的process_request方法的

# 多箇中介軟體,Django是如何執行其中的process_request方法的

# 自定義中介軟體
class MyMid(MiddlewareMixin):
    def process_request(self, request):
        print('我是來自第一個中介軟體的request的訊息')


class MyMid2(MiddlewareMixin):
    def process_request(self, request):
        print('我是來自第二個中介軟體的request的訊息')
       
# 中介軟體配置
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',
    'app1.mymiddleware.mymid.MyMid',
    'app1.mymiddleware.mymid.MyMid2'
]

# 檢視函式
def index(request):
    print('這是檢視函式的index')
    return HttpResponse('index')

# 訪問index控制檯輸出結果
我是來自第一個中介軟體的request的訊息
我是來自第二個中介軟體的request的訊息
這是檢視函式的index

# 結論
1.中介軟體的process_request方法是在執行檢視函式之前執行的
2.django在執行中介軟體的process_request方法是按照配置檔案從上到下的順序來的
3.不同中介軟體之間傳遞的request是同一個物件

【2】process_response

  • 定義process_response方法時,必須要傳入兩個形參,request和response。
  • 這個方法必須要返回response或者HttpResponse物件
  • response物件就是django檢視函式返回的物件
# 多箇中介軟體,Django是如何執行其中的process_response方法的

# 自定義中介軟體
class MyMid(MiddlewareMixin):
    def process_request(self, request):
        print('我是來自第一個中介軟體的request的訊息')

    def process_response(self, request, response):
        print('我是來自第一個中介軟體的響應訊息')
        return response


class MyMid2(MiddlewareMixin):
    def process_request(self, request):
        print('我是來自第二個中介軟體的request的訊息')

    def process_response(self, request, response):
        print('我是來自第二個中介軟體的響應訊息')
        return response

# 中介軟體配置
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',
    'app1.mymiddleware.mymid.MyMid',
    'app1.mymiddleware.mymid.MyMid2'
]

# 檢視函式
def index(request):
    print('這是檢視函式的index')
    return HttpResponse('index')

# 訪問index控制檯輸出結果
我是來自第一個中介軟體的request的訊息
我是來自第二個中介軟體的request的訊息
這是檢視函式的index
我是來自第二個中介軟體的響應訊息
我是來自第一個中介軟體的響應訊息

# 總結
1.這裡返回的resonse物件就是檢視函式返回的HttpResponse物件
2.執行的順序是按照配置列表從下到上執行的
3.不同中介軟體之間傳遞的response是同一個物件

【3】processs_view

  • 該方法有四個引數process_view(self, request, view_func, view_args, view_kwargs)
  • request就是和檢視函式的request物件是一樣的,
  • view_func是Django即將使用的檢視函式
  • view_args是將要傳遞給檢視函式的位置引數列表
  • view_kwargs是將要傳遞給檢視函式的關鍵字引數字典
  • Django在呼叫檢視函式之前回撥用process_view方法
  • 它應該返回一個None或者一個HttpResponse物件,如果返回None,將繼續執行其他中介軟體的processs_view方法,如果返回HttpResponse物件,Django將不在執行其他的業務邏輯,會直接掉頭從配置列表中最後一箇中介軟體的process_response開始依次執行
# 自定義中介軟體
class MyMid(MiddlewareMixin):
    def process_request(self, request):
        print('我是來自第一個中介軟體的request的訊息')

    def process_response(self, request, response):
        print('我是來自第一個中介軟體的響應訊息')
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print('------------------------------------------')
        print('我是來自第一個中介軟體的process_view')
        print(view_func, view_func.__name__)


class MyMid2(MiddlewareMixin):
    def process_request(self, request):
        print('我是來自第二個中介軟體的request的訊息')

    def process_response(self, request, response):
        print('我是來自第二個中介軟體的響應訊息')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('------------------------------------------')
        print('我是來自第二個中介軟體的process_view')
        print(view_func, view_func.__name__)
        
# 控制檯輸出
我是來自第一個中介軟體的request的訊息
我是來自第二個中介軟體的request的訊息
------------------------------------------
我是來自第一個中介軟體的process_view
<function index at 0x0000027D5FCA71A0> index
------------------------------------------
我是來自第二個中介軟體的process_view
<function index at 0x0000027D5FCA71A0> index
這是檢視函式的index
我是來自第二個中介軟體的響應訊息
我是來自第一個中介軟體的響應訊息

        
# 總結
1.process_view方法會在執行process_request方法之後,檢視函式之前執行
2.多箇中介軟體的process_view是按照配置檔案列表順序來執行的

【4】process_exception

  • 該方法有兩個引數,process_exception(self, request, exception)
  • 一個是request物件
  • 另一個exception是檢視函式發生異常而產生的Exception物件
  • 這個方法只有在檢視函式發生異常了還會執行,他的返回值可以是一個None也可以是一個HttpResponse物件
  • 如果是HttpResponse物件,Django將呼叫模板和中介軟體中的process_response方法,並且返回給瀏覽器。
  • 如果返回的是None,那麼將預設處理異常
# 自定義中介軟體
class MyMid(MiddlewareMixin):
    def process_request(self, request):
        print('我是來自第一個中介軟體的request的訊息')

    def process_response(self, request, response):
        print('我是來自第一個中介軟體的響應訊息')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('------------------------------------------')
        print('我是來自第一個中介軟體的process_view')
        print(view_func, view_func.__name__)

    def process_exception(self, request, exception):
        print(f'中介軟體1的錯誤訊息:>>>>>>{exception}')


class MyMid2(MiddlewareMixin):
    def process_request(self, request):
        print('我是來自第二個中介軟體的request的訊息')

    def process_response(self, request, response):
        print('我是來自第二個中介軟體的響應訊息')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('------------------------------------------')
        print('我是來自第二個中介軟體的process_view')
        print(view_func, view_func.__name__)

    def process_exception(self, request, exception):
        print(f'中介軟體2的錯誤訊息:>>>>>>{exception}')
        
# 檢視函式手動製造錯誤
def index(request):
    print('這是檢視函式的index')
    asdasdasd
    return HttpResponse('index')

# 訪問index控制檯輸出訊息
我是來自第一個中介軟體的request的訊息
我是來自第二個中介軟體的request的訊息
------------------------------------------
我是來自第一個中介軟體的process_view
<function index at 0x000001CACF6F7100> index
------------------------------------------
我是來自第二個中介軟體的process_view
<function index at 0x000001CACF6F7100> index
這是檢視函式的index
中介軟體2的錯誤訊息:>>>>>>name 'asdasdasd' is not defined
中介軟體1的錯誤訊息:>>>>>>name 'asdasdasd' is not defined
我是來自第二個中介軟體的響應訊息
我是來自第一個中介軟體的響應訊息

# 總結
1.process_exception方法只有在檢視函式丟擲異常後才會被呼叫
2.在丟擲異常的前提下,它是在執行完檢視函式之後被呼叫的
3.多箇中介軟體的process_exception方法是配置列表逆序執行的

【5】process_template_response

  • 這個方法用的比較少,它有兩個引數process_template_response(self, request, response)
  • 一個是request物件,另一個是TemplateResponse物件,由檢視函式後者中介軟體產生
  • process_template_response實在檢視函式執行完成之後立刻執行,但是他有一個條件,那就是檢視函式返回的物件有一個render()方法
# 自定義中介軟體
class MyMid(MiddlewareMixin):
    def process_request(self, request):
        print('我是來自第一個中介軟體的request的訊息')

    def process_response(self, request, response):
        print('我是來自第一個中介軟體的響應訊息')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('------------------------------------------')
        print('我是來自第一個中介軟體的process_view')
        print(view_func, view_func.__name__)

    def process_exception(self, request, exception):
        print(f'中介軟體1的錯誤訊息:>>>>>>{exception}')

    def process_template_response(self, request, response):
        print("MD1 中的process_template_response")
        return response


class MyMid2(MiddlewareMixin):
    def process_request(self, request):
        print('我是來自第二個中介軟體的request的訊息')

    def process_response(self, request, response):
        print('我是來自第二個中介軟體的響應訊息')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('------------------------------------------')
        print('我是來自第二個中介軟體的process_view')
        print(view_func, view_func.__name__)

    def process_exception(self, request, exception):
        print(f'中介軟體2的錯誤訊息:>>>>>>{exception}')

    def process_template_response(self, request, response):
        print("MD2 中的process_template_response")
        return response
    
# 檢視函式
def index(request):
    def render():
        print('我是檢視函式的render')
        return HttpResponse('無敵了孩子')

    print('這是檢視函式的index')
    rep = HttpResponse('index')
    rep.render = render
    return rep

# 控制檯輸出
我是來自第一個中介軟體的request的訊息
我是來自第二個中介軟體的request的訊息
------------------------------------------
我是來自第一個中介軟體的process_view
<function index at 0x0000020E5BE967A0> index
------------------------------------------
我是來自第二個中介軟體的process_view
<function index at 0x0000020E5BE967A0> index
這是檢視函式的index
MD2 中的process_template_response
MD1 中的process_template_response
我是檢視函式的render
我是來自第二個中介軟體的響應訊息
我是來自第一個中介軟體的響應訊息



【三】中介軟體執行流程

  • 請求到達中介軟體之後,先按照順序執行每個中介軟體的process_request方法
  • process_request方法返回值是None就以此執行,如果返回值是HttpResponse物件,那麼不在執行後面的process_request方法,而是將這個HttpResponse物件帶到當前這個中介軟體對應的process_response方法,在按照配置列表的逆序執行

img

  • process_request物件都執行完了之後,會進行匹配路由,匹配到路由之後會執行列表第一個中介軟體的process_view方法,如果所有的中介軟體的process_view方法返回的都是None,那麼將執行對應的檢視函式,如果有一箇中介軟體返回了HttpResponse物件,那麼將不執行檢視函式,之間從列表的最後一箇中介軟體的process_response物件開始執行

img

  • process_template_response和process_exception兩個方法的觸發是有條件的,執行順序也是倒序。總結所有的執行流程如下:

img

img

相關文章