ミドルウェア—Djangoドキュメント

提供:Dev Guides
< DjangoDjango/docs/2.2.x/topics/http/middleware
移動先:案内検索

ミドルウェア

ミドルウェアは、Djangoの要求/応答処理へのフックのフレームワークです。 これは、Djangoの入力または出力をグローバルに変更するための軽量で低レベルの「プラグイン」システムです。

各ミドルウェアコンポーネントは、特定の機能を実行する責任があります。 たとえば、Djangoには、セッションを使用してユーザーをリクエストに関連付けるミドルウェアコンポーネント AuthenticationMiddleware が含まれています。

このドキュメントでは、ミドルウェアのしくみ、ミドルウェアをアクティブ化する方法、および独自のミドルウェアを作成する方法について説明します。 Djangoには、箱から出してすぐに使用できる組み込みのミドルウェアが付属しています。 これらは、組み込みミドルウェアリファレンスに記載されています。

独自のミドルウェアを書く

ミドルウェアファクトリは、get_response呼び出し可能オブジェクトを受け取り、ミドルウェアを返す呼び出し可能オブジェクトです。 ミドルウェアは、ビューと同じように、要求を受け取り、応答を返す呼び出し可能オブジェクトです。

ミドルウェアは、次のような関数として記述できます。

def simple_middleware(get_response):
    # One-time configuration and initialization.

    def middleware(request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

    return middleware

または、次のように、インスタンスを呼び出すことができるクラスとして記述できます。

class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = self.get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

Djangoによって提供されるget_response呼び出し可能オブジェクトは、実際のビュー(これが最後にリストされたミドルウェアの場合)であるか、チェーン内の次のミドルウェアである可能性があります。 現在のミドルウェアは、それが正確に何であるかを知る必要も気にする必要もありません。それは次に来るものを表すだけです。

上記は少し単純化したものです。チェーンの最後のミドルウェアに対して呼び出し可能なget_responseは実際のビューではなく、ビューミドルウェアの適用を処理するハンドラーからのラッパーメソッドです。 、適切なURL引数を使用してビューを呼び出し、 template-response および exception ミドルウェアを適用します。

ミドルウェアは、Pythonパスのどこにでも存在できます。

__init__(get_response)

ミドルウェアファクトリは、get_response引数を受け入れる必要があります。 ミドルウェアのグローバル状態を初期化することもできます。 いくつかの注意点に注意してください。

  • Djangoはget_response引数のみでミドルウェアを初期化するため、__init__()を他の引数が必要であると定義することはできません。
  • リクエストごとに1回呼び出される__call__()メソッドとは異なり、__init__()は、Webサーバーの起動時に 1回のみ呼び出されます。


ミドルウェアを未使用としてマークする

起動時にミドルウェアを使用する必要があるかどうかを判断すると便利な場合があります。 このような場合、ミドルウェアの__init__()メソッドで MiddlewareNotUsed が発生する可能性があります。 次に、Djangoはそのミドルウェアをミドルウェアプロセスから削除し、:setting: `DEBUG`Trueの場合、デバッグメッセージを django.request ロガーに記録します。


ミドルウェアのアクティブ化

ミドルウェアコンポーネントをアクティブ化するには、Django設定の:setting: `MIDDLEWARE` リストに追加します。

:setting: `MIDDLEWARE` では、各ミドルウェアコンポーネントは文字列(ミドルウェアファクトリのクラスまたは関数名への完全なPythonパス)で表されます。 たとえば、によって作成されるデフォルト値は次のとおりです。 :djadmin: `django-admin startproject `

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

Djangoのインストールにはミドルウェアは必要ありません— :setting: `MIDDLEWARE` は、必要に応じて空にすることができます—ただし、少なくとも CommonMiddleware を使用することを強くお勧めします。

ミドルウェアは他のミドルウェアに依存する可能性があるため、:setting: `MIDDLEWARE` の順序は重要です。 たとえば、 AuthenticationMiddleware は、認証されたユーザーをセッションに保存します。 したがって、 SessionMiddleware の後に実行する必要があります。 Djangoミドルウェアクラスの順序に関する一般的なヒントについては、ミドルウェアの順序を参照してください。


ミドルウェアの順序と階層化

リクエストフェーズでは、ビューを呼び出す前に、Djangoは:setting: `MIDDLEWARE` で定義されている順序でミドルウェアをトップダウンで適用します。

これはタマネギのように考えることができます。各ミドルウェアクラスは、タマネギのコアにあるビューをラップする「レイヤー」です。 リクエストがタマネギのすべてのレイヤーを通過する場合(それぞれがget_responseを呼び出してリクエストを次のレイヤーに渡す)、コアのビューに至るまで、レスポンスはすべてのレイヤーを通過します(逆の順序で)帰り道。

レイヤーの1つが、get_responseを呼び出さずに短絡して応答を返すことを決定した場合、そのレイヤー内のタマネギのレイヤー(ビューを含む)はいずれも要求または応答を認識しません。 応答は、要求が通過したのと同じレイヤーを介してのみ返されます。


その他のミドルウェアフック

前述の基本的な要求/応答ミドルウェアパターンに加えて、クラスベースのミドルウェアに他の3つの特別なメソッドを追加できます。

process_view()

process_view(request, view_func, view_args, view_kwargs)

requestHttpRequest オブジェクトです。 view_funcは、Djangoが使用しようとしているPython関数です。 (これは実際の関数オブジェクトであり、文字列としての関数の名前ではありません。)view_argsはビューに渡される位置引数のリストであり、view_kwargsはキーワードの辞書です。ビューに渡される引数。 view_argsview_kwargsも、最初のビュー引数(request)を含みません。

process_view()は、Djangoがビューを呼び出す直前に呼び出されます。

Noneまたは HttpResponse オブジェクトのいずれかを返す必要があります。 Noneを返す場合、Djangoはこのリクエストの処理を続行し、他のprocess_view()ミドルウェアを実行してから、適切なビューを実行します。 HttpResponse オブジェクトを返す場合、Djangoはわざわざ適切なビューを呼び出すことはありません。 その HttpResponse に応答ミドルウェアを適用し、結果を返します。

ノート

ビューが実行される前にミドルウェア内またはprocess_view()request.POST にアクセスすると、ミドルウェアがリクエストのアップロードハンドラーを変更できないようになります。通常は避ける必要があります。

CsrfViewMiddleware クラスは、 csrf_exempt()および csrf_protect()デコレータを提供し、ビューがどの時点でCSRFを明示的に制御できるかを示すため、例外と見なすことができます。検証が行われる必要があります。


process_exception()

process_exception(request, exception)

requestHttpRequest オブジェクトです。 exceptionは、view関数によって生成されたExceptionオブジェクトです。

ビューで例外が発生すると、Djangoはprocess_exception()を呼び出します。 process_exception()は、Noneまたは HttpResponse オブジェクトのいずれかを返す必要があります。 HttpResponse オブジェクトを返す場合、テンプレートの応答と応答ミドルウェアが適用され、結果の応答がブラウザーに返されます。 それ以外の場合は、デフォルトの例外処理が開始されます。

この場合も、ミドルウェアは、process_exceptionを含む応答フェーズ中に逆の順序で実行されます。 例外ミドルウェアが応答を返す場合、そのミドルウェアより上のミドルウェアクラスのprocess_exceptionメソッドはまったく呼び出されません。


process_template_response()

process_template_response(request, response)

requestHttpRequest オブジェクトです。 responseは、Djangoビューまたはミドルウェアによって返される TemplateResponse オブジェクト(または同等のもの)です。

process_template_response()は、応答インスタンスにrender()メソッドがある場合、ビューの実行が終了した直後に呼び出され、 TemplateResponse または同等のものであることを示します。

renderメソッドを実装する応答オブジェクトを返す必要があります。 response.template_nameresponse.context_dataを変更して、指定されたresponseを変更するか、新しい TemplateResponse または同等のものを作成して返すことができます。

応答を明示的にレンダリングする必要はありません。すべてのテンプレート応答ミドルウェアが呼び出されると、応答は自動的にレンダリングされます。

ミドルウェアは、process_template_response()を含む応答フェーズ中に逆の順序で実行されます。


ストリーミング応答の処理

HttpResponse とは異なり、 StreamingHttpResponse にはcontent属性がありません。 その結果、ミドルウェアは、すべての応答にcontent属性があると想定できなくなりました。 コンテンツにアクセスする必要がある場合は、ストリーミング応答をテストし、それに応じて動作を調整する必要があります。

if response.streaming:
    response.streaming_content = wrap_streaming_content(response.streaming_content)
else:
    response.content = alter_content(response.content)

ノート

streaming_contentは、メモリに保持するには大きすぎると見なす必要があります。 応答ミドルウェアはそれを新しいジェネレーターでラップするかもしれませんが、それを消費してはなりません。 ラッピングは通常、次のように実装されます。

def wrap_streaming_content(content):
    for chunk in content:
        yield alter_content(chunk)

例外処理

Djangoは、ビューまたはミドルウェアによって発生した例外を、エラーステータスコードを含む適切なHTTP応答に自動的に変換します。 特定の例外は4xxステータスコードに変換されますが、不明な例外は500ステータスコードに変換されます。

この変換は各ミドルウェアの前後で行われるため(タマネギの各層の間の薄膜と考えることができます)、すべてのミドルウェアは常に [の呼び出しから何らかのHTTP応答を取得することに依存できます。 X241X]呼び出し可能。 ミドルウェアは、get_responseへの呼び出しをtry/exceptでラップし、後のミドルウェアまたはビューによって発生した可能性のある例外を処理することを心配する必要はありません。 たとえば、チェーン内の次のミドルウェアで Http404 例外が発生した場合でも、ミドルウェアはその例外を認識しません。 代わりに、 status_code が404の HttpResponse オブジェクトを取得します。


Django1.10以前のスタイルのミドルウェアのアップグレード

class django.utils.deprecation.MiddlewareMixin

Djangoはdjango.utils.deprecation.MiddlewareMixinを提供して、:setting: `MIDDLEWARE` と古いMIDDLEWARE_CLASSESの両方と互換性のあるミドルウェアクラスの作成を容易にします。 Djangoに含まれるすべてのミドルウェアクラスは、両方の設定と互換性があります。

ミックスインは、オプションのget_response引数を受け入れ、それをself.get_responseに格納する__init__()メソッドを提供します。

__call__()メソッド:

  1. self.process_request(request)を呼び出します(定義されている場合)。
  2. self.get_response(request)を呼び出して、後のミドルウェアとビューから応答を取得します。
  3. self.process_response(request, response)を呼び出します(定義されている場合)。
  4. 応答を返します。

MIDDLEWARE_CLASSESと一緒に使用する場合、__call__()メソッドは使用されません。 Djangoはprocess_request()process_response()を直接呼び出します。

ほとんどの場合、このミックスインから継承するだけで、古いスタイルのミドルウェアを新しいシステムと互換性があり、十分な下位互換性があります。 新しい短絡セマンティクスは、既存のミドルウェアにとって無害であるか、さらには有益です。 場合によっては、ミドルウェアクラスは、新しいセマンティクスに適応するためにいくつかの変更が必要になることがあります。

:setting: `MIDDLEWARE`MIDDLEWARE_CLASSESを使用した場合の動作の違いは次のとおりです。

  1. MIDDLEWARE_CLASSESでは、以前のミドルウェアがprocess_requestメソッドからの応答を返すことで短絡した場合でも、すべてのミドルウェアで常にprocess_responseメソッドが呼び出されます。 :setting: `MIDDLEWARE` の下では、ミドルウェアはタマネギのように動作します。応答が途中で通過するレイヤーは、途中でリクエストを確認したレイヤーと同じです。 ミドルウェアが短絡した場合、そのミドルウェアとその前の:setting: `MIDDLEWARE` のミドルウェアのみが応答を確認します。
  2. MIDDLEWARE_CLASSESでは、process_exceptionは、ミドルウェアprocess_requestメソッドから発生した例外に適用されます。 :setting: `MIDDLEWARE` では、process_exceptionは、ビューから(または TemplateResponserenderメソッドから)発生した例外にのみ適用されます。 ミドルウェアから発生した例外は、適切なHTTP応答に変換されてから、次のミドルウェアに渡されます。
  3. MIDDLEWARE_CLASSESでは、process_responseメソッドで例外が発生した場合、以前のすべてのミドルウェアのprocess_responseメソッドはスキップされ、500 Internal Server Error HTTP応答が常に返されます(発生した例外がeg Http404 )。 :setting: `MIDDLEWARE` の下で、ミドルウェアから発生した例外はすぐに適切なHTTP応答に変換され、次のミドルウェアはその応答を確認します。 ミドルウェアが例外を発生させたためにミドルウェアがスキップされることはありません。