【Django】Middlewareミドルウェアとは(有効化、構造、実行されるタイミング)

2021.08.31 /

【Django】Middlewareミドルウェアとは(有効化、構造、実行されるタイミング)

本記事ではPythonのフレームワークであるDjangoにおける、Middlewareミドルウェアについて解説していきます。

DjangoはフルスタックのWebフレームワークであるため、初めから様々な機能が備えられています。

IT用語の確認

フルスタックとは、ウェブサイト(Webサービス)を作成するために必要な機能がすべて備えられていることを意味します

そのためDjango初心者の方にとっては、Djangoスクリプトには理解が難しい記述がたくさんあります。例えばsettings.py。最初からたくさんの記述がありますが、初めての方だとほとんどの記述の意味が分からないと思います。

このsettings.pyにはMiddlewareについての記述があります。このミドルウェアがそもそもなんなのか、よくわからずに利用している方も多いかと思います。

WebフレームワークのDjangoにおける、Middlewareの仕組みについて理解を深めていきましょう。

Middleware(ミドルウェア)

Middleware(ミドルウェア)とは

DjangoにおけるMiddleware(ミドルウェア)とは、
Djangoのリクエスト/レスポンス処理の前後でフックを加える仕組みです。

IT用語の確認

フック(hook)とは、プログラムの特定箇所にユーザーが作成した処理を追加して実行する仕込みのこと

例えば、サイトにアクセスされたときにログを出力する、現在のセッション情報を取り出すといった処理をミドルウェアで実装できます。

Middlewareを利用する理由の一つに処理の共通化があります。

views.py内の各ビュー関数で重複する処理がある場合、それをMiddlewareで共通化すると可読性の向上やビュー関数の肥大化を抑えることができます。

Middlewareの最初の理解として、Middlewareとは各ビュー関数で共通して行いたい処理を記述するものとして覚えてください。

ビュー関数の処理を共通化する仕組みは次の3つがあり、本記事ではMiddlewareについて解説します。

  • Middleware
  • デコレーター
  • クラスベースビューまたはMixin

ミドルウェアの有効化

ミドルウェアは設定ファイル(settings.py)に追加することで有効化されます。
次のようにsettings.pyのMIDDLEWAREリストに記述します。

MIDDLEWARE = []

作成したミドルウェアはここに追加しない限り、利用することはできません。

組み込みMiddleware

Djangoには最初から使用できるミドルウェアがいくつか用意されています。
これを組み込みMiddlewareと呼びます。

組み込みMiddlewareの種類は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にはリクエスト・レスポンスのセキュリティを強化するSecurityMiddleware、セッションを有効にするSessionMiddleware、アクセス制限を行うCommonMiddlewareなど有用なミドルウェアがあります。

公式ではCommonMiddlewareの使用を強く勧めています。

Middleware(ミドルウェア)の構造

クラスの定義

ミドルウェアはスクリプト内にクラスで定義されます。

ミドルウェアクラスは以下コードをベースとして作成されます。

class クラス名:
    def __init__(self, get_response):
        self.get__response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        return response

上記のベースコードに実行したい処理を追加することで、リクエスト/レスポンス処理の前後で実行されます。

ミドルウェアに追加した処理が実行されるタイミングについては次項で解説いたします。

Middleware処理の実行されるタイミング(フックポイント)

ミドルウェアに追加したプログラムがフックされるタイミング(フックポイント)は、ベースコードへ追記した場所によって異なります。

class クラス名:
    def __init__(self, get_response):
        self.get__response = get_response
        # ここに処理を記述すると、サーバーが起動したときのみ実行される

    def __call__(self, request):
        # ここに処理を記述すると、view関数が実行される前に実行される
        response = self.get_response(request)
	# ここに処理を記述すると、view関数が実行された後に実行される
        return response

上記のようにフックされるタイミングは3つあります。
各タイミングについて以下で詳しく解説していきます。

__init__()内

__init__()はWebサーバー起動時のみに実行されます。

そのためサーバー起動時の一回のみ実行したい処理は__init__()内に記述します。
主に初期化などで使われます。

__init__()は引数にget_responseを受け取ります。

__call__()の直下(get_responseより前)

__call__()はリクエストがある度に呼び出されます。
そのため、__call__()内に記述した処理はリクエスト毎に実行されます。

__call__()はリクエスト(HttpRequestオブジェクト)を受け取り、レスポンス(HttpResponseオブジェクト)をreturnで返します。

__call()__内でも記述する箇所によって、実行されるタイミングが異なります。

__call__()の直下(get_responseより前)に記述した処理は、view関数が呼ばれる前に実行されます。

self.get_response()は引数にリクエストを指定することで、view関数を実行したレスポンスを取得します。

__call__()内のreturn前(get_responseの後)

__call__()内のreturn前(get_responseの後)に記述した処理は、view関数が実行された後に実行されます。

その他のフックポイント

すでに既述しているフックポイントの他に次のメソッド(特殊メソッド)を使うことで、別のフックポイントを追加することができます。

  • process_view:ビュー関数を呼ぶ前にフック
  • process_exception:ビュー関数が例外をraiseした時にフック
  • process_template_response:view関数実行後にTemplateResponseオブジェクトを返した時にフック

これらを使ってMiddlewareクラス内に新たなフックポイントを追加することができます。

Middlewareを独自に作成(自作)する方法

ミドルウェアは自分で作成することで、そのWebアプリケーションに合ったものを作ることができます。

ミドルウェアを自作することでコードの可読性もよくなり、コード量も減らすことができますのでぜひ挑戦してみてください。

ミドルウェアの自作については以下記事をご参照ください。

まとめ

本記事「【Django】Middlewareミドルウェアとは(有効化、構造、実行されるタイミング)」はいかがでしたか。

ミドルウェアを使いこなして、様々な処理をうまく共通化できるようになりましょう。