============= ミドルウェア ============= :revision-up-to: 17812 (1.4) ミドルウェア (Middleware) とは、 Django のリクエスト/レスポンス処理をフック するためのフレームワークです。ミドルウェアは軽量かつ低水準な「プラグイン」 システムで、Django の入出力を操作します。 各ミドルウェアコンポーネントはそれぞれ特定の機能を担っています。例えば、 Django には ``XViewMiddleware`` ミドルウェアコンポーネントがありますが、こ れは全ての ``HEAD`` リクエストに対して ``"X-View"`` HTTP ヘッダを追加します。 このドキュメントでは、 Django についてくる全てのミドルウェアコンポーネント の使用法と、自分で新たにミドルウェアを作る方法を説明します。 Django には、すぐに使える組み込みのミドルウェアが付属しています。 :ref:`組み込みミドルウェアガイド ` を参照してください。 ミドルウェアの有効化 ==================== ミドルウェアコンポーネントを有効化するには、Django 設定ファイルの :setting:`MIDDLEWARE_CLASSES` リストにコンポーネントを追加します。コンポー ネント名は文字列で指定し、ミドルウェアのクラス名を完全な Python パスで表し ます。例えば、 :djadmin:`django-admin.py startproject ` が生 成するデフォルトの設定ファイルにある :setting:`MIDDLEWARE_CLASSES` は以下の ようになっています:: MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', ) リクエストの処理フェーズでは、Django は :setting:`MIDDLEWARE_CLASSES` に指定された順番で (:meth:`process_request` および :meth:`process_view``) ミドルウェアを適用していきます。レスポンスの処理フェーズでは、 (:meth:`process_response` および :meth:`process_exception` ) ミドルウェア が逆順に適用されます。この仕組みは、タマネギの構造になぞらえて、ミドルウェ アクラスを「層」だと考えるとよいでしょう: .. image:: _images/middleware.png :width: 502 :height: 417 :alt: Middleware application order. Django はミドルウェアがなくても動作します -- 望むなら :setting:`MIDDLEWARE_CLASSES` は空でもよいのです。とはいえ、少なくとも :class:`~django.middleware.common.CommonMiddleware` は使うように強く勧めます。 ミドルウェアを自作する ====================== ミドルウェアの自作は簡単です。各ミドルウェアコンポーネントは、以下のメソッ ドを少なくとも一つ定義しているような単一の Python クラスです: .. _request-middleware: ``process_request`` ------------------- .. method:: process_request(self, request) ``request`` は :class:`~django.http.HttpRequest` オブジェクトです。このメソッ ドはリクエストごとに Django がどのビューを実行するか決定する前に呼び出されます。 ``process_request()`` は ``None`` または :class:`~django.http.HttpResponse` オブジェクトのいずれかを返さねばなりません。 ``None`` を返した場合、 Django はリクエストの処理を継続し、他のミドルウェアや適切なビューを実行します。 :class:`~django.http.HttpResponse` オブジェクトを返した場合、 Django は他の リクエストミドルウェア、ビューミドルウェア、例外ミドルウェア、あるいは URLconf で設定されたビューを呼び出さず、 :class:`~django.http.HttpResponse` オブジェクトをそのまま返します。レスポンスミドルウェアは必ず呼び出されます。 .. _view-middleware: ``process_view`` ---------------- .. method:: process_view(self, request, view_func, view_args, view_kwargs) ``request`` は :class:`~django.http.HttpRequest` オブジェクトです。 ``view_func`` は Django がビュー関数としてこれから呼び出そうとしている Python の関数です、 (実際の関数オブジェクトで、関数名を表す文字列ではありま せん)。 ``view_args`` にはビューに渡されることになる固定引数が、 ``view_kwargs`` にはビューに渡されることになるキーワード引数の辞書が入って います。 ``view_args`` と``view_kwargs`` のいずれにも、ビューの第一引数 (``request``) は入っていません。 ``process_view()`` は Django がビュー関数を呼び出す直前に呼び出されます。こ の関数は ``None`` または :class:`~django.http.HttpResponse` オブジェクトを 返さねばなりません。 ``None`` を返した場合、 Django は処理を継続し、他のミ ドルウェアの ``process_view()`` を試した後、適切なビュー関数を呼び出します。 :class:`~django.http.HttpResponse` オブジェクトを返した場合、 Django は他の リクエストミドルウェア、ビューミドルウェア、例外ミドルウェア、あるいは URLconf で設定されたビューを呼び出さず、 :class:`~django.http.HttpResponse` オブジェクトをそのまま返します。レスポンスミドルウェアは必ず呼び出されます。 .. note:: ``process_request`` や``process_view`` からミドルウェアの中の :attr:`request.POST ` や :attr:`request.REQUEST ` にアクセスするとそのミドルウェアの後で実行される任意のビューが :ref:`リクエストのアップロードハンドラーを動的に変更する ` ことができなくなるので避けるべきです。 :class:`~django.middleware.csrf.CsrfViewMiddleware` クラスは例外と 考えることができます。 :func:`~django.views.decorators.csrf.csrf_exempt` デコレータと :func:`~django.views.decorators.csrf.csrf_protect` デコレータでは ビューはCSRF検証が行われる時点で明示的に制御することができるからです。 .. _template-response-middleware: ``process_template_response`` ----------------------------- .. versionadded:: 1.3 .. method:: process_template_response(self, request, response) ``request`` は :class:`~django.http.HttpRequest` クラスのオブジェクトです。 ``response`` は :class:`~django.template.response.SimpleTemplateResponse` クラスのサブクラス (例えば :class:`~django.template.response.TemplateResponse`) 、あるいは ``render`` メソッドを実装する任意の response オブジェクトです。 ``process_template_response()`` は ``render`` メソッドを実装する response オブジェクト返さなければいけません。 与えられた ``response`` の ``response.template_name`` と ``response.context_data`` を変更することができますが、 全くあたらしい :class:`~django.template.response.SimpleTemplateResponse` か同等のものを 作成することも可能です。 ``process_template_response()`` は response インスタンスが ``render()`` メソッド を持っている時、つまりそのresponse が :class:`~django.template.response.TemplateResponse` クラス、あるいは同等のクラス であるのみ呼び出されます。 明示的にresponseをレンダする必要はありません。 -- 全てのテンプレート応答ミドルウェア が呼び出された時に1度だけ自動的にresponseがレンダされます。 応答フェーズの間、ミドルウェアは逆順で実行されます。 process_template_response もそれに含まれます。 .. _response-middleware: ``process_response`` -------------------- .. method:: process_response(self, request, response) ``request`` は :class:`~django.http.HttpRequest` オブジェクトです。 ``response`` は Django のビュー関数の返す :class:`~django.http.HttpResponse` オブジェクトです。 ``process_response()`` は :class:`~django.http.HttpResponse` オブジェクトを 返さねばなりません。渡された ``response`` オブジェクトを変更して返しても良いですし、 新たに :class:`~django.http.HttpResponse` オブジェクトを生成して返すことも可能です。 ``process_request()`` や ``process_view()`` メソッドとは異なって、 ``process_response()`` メソッドは必ず呼ばれます。 同じミドルウェアクラスの ``process_request()`` や ``process_view()`` メソッド がスキップされても呼ばれます。これより先に呼ばれるミドルウェアメソッドが :class:`~django.http. httpresponse` クラスを返していたからです(つまり、例えば ``process_response()`` メソッドは ``process_request()`` でセットアップが 完了していることを前提としてはいけない、ということです。) さらに、レスポンスフェーズの間はクラスは逆順、つまり下から上に適用されます。 これは :setting:`MIDDLEWARE_CLASSES` の最後に定義されたクラスが最初に 実行されるという意味です。 .. _exception-middleware: ``process_exception`` --------------------- .. method:: process_exception(self, request, exception) ``request`` は :class:`~django.http.HttpRequest` オブジェクトです。 ``exception`` はビュー関数の送出した ``Exception`` オブジェクトです。 Django はビューが例外を送出した際に ``process_exception()`` を呼び出します。 ``process_exception()`` は ``None`` または :class:`~django.http.HttpResponse` オブジェクトのいずれかを返さねばなりませ ん。 :class:`~django.http.HttpResponse` オブジェクトを返した場合、その応答 をそのままブラウザに返します。それ以外の場合、デフォルトの例外処理を起動し ます。 ここでも応答フェーズの間はミドルウエアは逆順で実行されます。 ``process_exception`` もそれに含まれます。 もしも例外ミドルウェアが応答を返すのであれば、 そのミドルウェアより上位にあるミドルウェアクラスは決して呼ばれることはありません。 ``__init__`` ------------ ほとんどのミドルウェアクラスは、実質的に単なる ``process_*`` メソッドの置き 場でしかないので、初期化メソッドは必要ありません。ミドルウェアのグローバル な状態を保存するのに ``__init__`` メソッドを使ってもかまいませんが、以下の 点に注意してください: * Django はミドルウェアクラスを引数なしで初期化するので、 ``__init__`` には必須の引数を定義できません。 * ``process_*`` メソッドはリクエストごとに呼び出されますが、 ``__init__`` は Web サーバの起動時に *一度* しか呼び出されません。 ミドルウェアを動的に有効にする ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ミドルウェアを使うかどうかを実行時に決められると便利なことがあります。ミド ルウェアの ``__init__`` メソッドで :exc:`django.core.exceptions.MiddlewareNotUsed` を送出すると、 Django はそ のミドルウェアを処理から外します。 ガイドライン ------------ * ミドルウェアのクラスはサブクラスでなくてもかまいません。 * ミドルウェアのクラスはPython のモジュールパス上のどこにでも置けます。 Django にとって必要なのは :setting:`MIDDLEWARE_CLASSES` にクラスへの パスが指定されていることだけです。 * :mod:`Django で使えるミドルウェア ` を参考にしてく ださい。 * 自分の書いたミドルウェアコンポーネントが他の人にとっても有用だと思っ たなら、ぜひ :ref:`コミュニティにコントリビュート ` してください!知らせてくだされば、 Django に追加するか検討します。