Django ミドルウェア

Django ミドルウェアは、Django の request または response オブジェクトを変更するフックであり、HttpRequest と HttpResponse の処理の間にある処理プロセスと理解できます。

ブラウザがリクエストしてからレスポンスを受け取るまでの過程で、Django は多くのミドルウェアを通じて処理する必要があります。下図のようになります。

Django ミドルウェアの役割:

  • リクエストを変更する、つまり view に渡される HttpRequest オブジェクトを変更します。
  • レスポンスを変更する、つまり view が返す HttpResponse オブジェクトを変更します。

ミドルウェアコンポーネントは settings.py ファイルの MIDDLEWARE オプションリストに設定します。

設定内の各文字列オプションはクラスであり、つまり 1 つのミドルウェアです。

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',
]

カスタムミドルウェア

ミドルウェアは 4 つのメソッドを定義できます。それぞれ以下のとおりです。

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

カスタムミドルウェアの手順:

app ディレクトリに新しい py ファイルを作成し、名前は任意に決めます。その py ファイルで MiddlewareMixin をインポートします:

from django.utils.deprecation import MiddlewareMixin

カスタムミドルウェアクラスは、親クラス MiddlewareMixin を継承する必要があります:

class MD1(MiddlewareMixin): 
    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',
   
    'app01.middlewares.MD1',
]

カスタムミドルウェアク​​ラスのメソッド

カスタムミドルウェアク​​ラスのメソッドには、process_request と process_response があります。

process_request メソッド

process_request メソッドには request という 1 つのパラメータがあります。この request はビュー関数の request と同じものです。

process_request メソッドの戻り値は、None または HttpResponse オブジェクトです。

  • 戻り値が None の場合は、通常のフローで続行し、次のミドルウェアに処理を渡します。
  • 戻り値が HttpResponse オブジェクトの場合、Django は後続のビュー関数の前に実行するメソッドとビュー関数を実行せず、そのミドルウェアを起点としてミドルウェアを逆順に実行し、実行するのはビュー関数の後に実行するメソッドです。

process_request メソッドはビュー関数の前に実行されます。

複数のミドルウェアを設定する場合、MIDDLEWARE の登録順序、つまりリストのインデックス値に従って順番に実行されます。

異なるミドルウェア間で渡される request パラメータはすべて同じリクエストオブジェクトです。

例

from django.utils.deprecation import MiddlewareMixin

from django.shortcuts import render, HttpResponse

class MD1(MiddlewareMixin):
    def process_request(self, request):
       print("md1 process_request メソッド。", id(request)) #ビューの前に実行

process_response

process_response メソッドには 2 つのパラメータがあります。1 つは request、もう 1 つは response です。request はリクエストオブジェクト、response はビュー関数が返す HttpResponse オブジェクトです。このメソッドは戻り値を持つ必要があり、かつ response である必要があります。

process_response メソッドはビュー関数の後に実行されます。

複数のミドルウェアを設定する場合、MIDDLEWARE の登録順序、つまりリストのインデックス値に従って逆順に実行されます。

例

class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("md1 process_request メソッド。", id(request)) #ビューの前に実行


    def process_response(self,request, response): :#リクエストレスポンスに基づく
        print("md1 process_response メソッド!", id(request)) #ビューの後
        return response

下図からわかるように、通常の場合は緑色のルートに沿って実行されます。仮にミドルウェア 1戻り値がある場合は、赤色のルートに沿って進み、そのクラスの process_response メソッドを直接実行して返します。後続の他のミドルウェアは実行されません。

process_view

process_view メソッドの形式は次のとおりです。

process_view(request, view_func, view_args, view_kwargs)
process_view メソッドには 4 つのパラメータがあります。

  • request は HttpRequest オブジェクトです。
  • view_func は Django がこれから使用するビュー関数です。
  • view_args はビューに渡される位置引数のリストです。
  • view_kwargs はビューに渡されるキーワード引数のディクショナリです。

view_args と view_kwargs はどちらも最初のビューパラメータ(request)を含みません。

process_view メソッドはビュー関数の前、process_request メソッドの後に実行されます。

戻り値は、None、view_func(request)、または HttpResponse オブジェクトです。

  • 戻り値が None の場合は、通常のフローで続行し、次のミドルウェアに処理を渡します。
  • 戻り値が HttpResponse オブジェクトの場合、Django は後続のビュー関数の前に実行するメソッドとビュー関数を実行せず、そのミドルウェアを起点としてミドルウェアを逆順に実行し、実行するのはビュー関数の後に実行するメソッドです。
  • c. 戻り値が view_func(request) の場合、Django は後続のビュー関数の前に実行するメソッドを実行せず、ビュー関数を先に実行し、その後ビュー関数の後に実行するメソッドを逆順に実行します。
  • 最後のミドルウェアの process_request がルーティング関係のマッピングに到達した後、最初のミドルウェアの process_view に戻り、その後順に下っていってビュー関数に到達します。

    例

    class MD1(MiddlewareMixin):
        def process_request(self, request):
            print("md1 process_request メソッド。", id(request)) #ビューの前に実行


        def process_response(self,request, response): :#リクエストレスポンスに基づく
            print("md1 process_response メソッド!", id(request)) #ビューの後
            return response


        def process_view(self,request, view_func, view_args, view_kwargs):
            print("md1 process_view メソッド!") #ビューの前に実行 順に実行
            #return view_func(request)

    process_exception

    process_exception メソッドは次のとおりです。

    process_exception(request, exception)

    パラメータの説明:

    • request は HttpRequest オブジェクトです。
    • exception はビュー関数の例外によって生成される Exception オブジェクトです。

    process_exception メソッドは、ビュー関数で例外が発生した場合にのみ実行され、settings の登録順の逆順で実行されます。

    ビュー関数の後、process_response メソッドの前に実行されます。

    process_exception メソッドの戻り値は、None または HttpResponse オブジェクトです。

    戻り値が None の場合、ページは 500 ステータスコードのエラーを報告し、ビュー関数は実行されません。

    process_exception メソッドが逆順に実行され、その後 process_response メソッドが逆順に実行されます。

    戻り値が HttpResponse オブジェクトの場合、ページはエラーにならず、ステータスコード 200 を返します。

    ビュー関数は実行されず、そのミドルウェアの後続の process_exception メソッドも実行されません。最後のミドルウェアの process_response メソッドから直接逆順に実行が始まります。

    process_view メソッドがビュー関数を返し、ビュー関数が先に実行され、かつビュー関数でエラーが発生した場合、process_exception メソッドの戻り値が何であってもページはエラーを報告し、 かつビュー関数と process_exception メソッドはどちらも実行されません。

    最後のミドルウェアの process_response メソッドから直接逆順に実行されます:

    例

    class MD1(MiddlewareMixin):
        def process_request(self, request):
            print("md1 process_request メソッド。", id(request)) #ビューの前に実行

        def process_response(self,request, response): :#リクエストレスポンスに基づく
            print("md1 process_response メソッド!", id(request)) #ビューの後
            return response

        def process_view(self,request, view_func, view_args, view_kwargs):
            print("md1 process_view メソッド!") #ビューの前に実行 順に実行
            #return view_func(request)


        def process_exception(self, request, exception):#エラーを発生させるとこのメソッドがトリガーされます
            print("md1 process_exception メソッド!")
            # return HttpResponse(exception) #エラー情報を返す

    その他の拡張