Djangoでmiddleware(ミドルウェア)を自作する方法

2022年1月7日Djangoの豆知識ミドルウェア

ミドルウェアとは?

ミドルウェアというといろんな意味がありますが、今回は「Djangoがさまざまなパス(URL)のリクエストをさばくときに、共通で処理をするもの」とします。

サンプルコード

Githubにサンプルコードがあります。ターミナルで

git clone -b custom-middleware https://github.com/yeconnect/django-baby-starter-template.git

バージョン

Python 3.9です

django==3.2

参考

Django公式「ミドルウェア

ミドルウェアの設定方法

今回のコードではプロジェクトをconfig、アプリケーションをtodoとしています。

ミドルウェアのコードを記載する場所はどこでも良いですが、今回は以下のようなディレクトリとし、ルートにmiddlewareディレクトリを作成し、その中に__init__.py(空で良い)と、sample_middleware.pyを作成しました。

.
├── Dockerfile
├── README.md
├── config
│   ├── __init__.py
│   ├── __pycache__
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── docker-compose.yml
├── manage.py
├── middleware
│   ├── __init__.py
│   ├── __pycache__
│   └── sample_middleware.py
├── requirements.txt
└── todo
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations
    ├── models.py
    ├── tests.py
    └── views.py

それでは、ミドルウェア本体を定義します。sample_middleware.pyに以下の記述をします。

class SampleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        print('サーバー起動のときのみ')

    def __call__(self, request):
        # ここにviews.pyの前にしたい処理を記述
        print('1: リクエストがviews.pyで処理される前') # 例

        response = self.get_response(request)

        # ここにviews.pyの後にしたい処理を記述
        print('2: リクエストがviews.pyで処理された後') # 例

        return response

これをsettings.pyで読み込みます。40行目あたりにあるMIDDLEWARE = []に追加します。

MIDDLEWARE = [
    'middleware.sample_middleware.SampleMiddleware', # 今回の自作ミドルウェア
    '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.sample_middleware.SampleMiddlewareのように、middleware.ファイル名.クラス名で読み込めます。

実際に走らせてみる

サンプルコードで体験してみましょう。ターミナルで、

git clone -b custom-middleware https://github.com/yeconnect/django-baby-starter-template.git
cd django-baby-starter-template
docker compose up

とし、ブラウザで http://localhost:4989/todo/ を表示させます。

このURLでは、views.pyで

def sample_func(request):
    print('ここがviews.py、sample_funcなう')
    return HttpResponse('Hello World from todo app')

とprintさせるようにしています。

ターミナルを見ると

と表示されています。

解説

自作するミドルウェアクラスでは、以下の①、②、③の3つの記述ポイントがあります。

class SampleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # ① サーバー起動時にしたい処理をここに

    def __call__(self, request):
        # ② リクエスト処理前にしたい処理をここに

        response = self.get_response(request) # これはviews.pyでの処理を意味する

        # ③ リクエスト処理後にしたい処理をここに

        return response

ここからの記事では②を「前処理③を「後処理と言います。

ミドルウェアの実行される順番

ここまでは一つのミドルウェアについて見てきました。

Djangoでは、複数のミドルウェアを作ることもできます。その順番は、書く順番によって決まります。

MIDDLEWARE = [
    'ミドルウェアA', 
    'ミドルウェアB',
    'ミドルウェアC'
]

のように書いたとすると

ミドルウェアAの前処理 → ミドルウェアBの前処理 → ミドルウェアCの前処理 → views.pyでの処理 → ミドルウェアCの後処理 → ミドルウェアBの後処理 → ミドルウェアAの後処理

のようになります。Django公式では「views.pyが中央のコアにある、玉ねぎのような構造」とあります。

おまけ

この自作ミドルウェアを応用して「Djangoがレスポンスを返すまでにかかった時間を測定してみた!」を作成しました。middlewareを実際に使うところが見たい場合はこちらをご覧ください。(サンプルコードもあります。)

スポンサーリンク