middleware がどう動くか実装をみる

前回セッションのバックエンド実装について書いた。

実際に使うときは、ミドルウェアで指定する必要がある。

Djangoミドルウェアは公式ドキュメントによると object を継承したクラスをかけばいいという。自分もちょっとだけ書いたことがある。ただこのとき、固定されたメソッド名をどう拾って処理できるようにしているか、あと object を継承していてどこから定義したものがつかえるのかよくわからなかった。

参考

おさらい

設定する

MIDDLEWARE_CLASSES でタブル内に文字列でクラスのパスを指定する。

Middleware | Django documentation | Django

実装する

先ほどの SessionMiddleware の場合こうなっている

django/middleware.py at master · django/django · GitHub

Python の object を継承したクラスをつくる。あと必要なメソッドを実装すればOK。 Middleware | Django documentation | Django によると以下の5つ

  • process_request
  • process_view
  • process_exception
  • process_template_response
  • process_response

SessionMiddleware の場合、 Django 読み込み時に backend のエンジンを読み込み、 SessionStore クラスのインスタンスを保持しておく。 リクエストが来たら都度 SessionStoreインスタンスを作成、レスポンスを返すときにもろもろの処理をはさんでいる。

実装をみる

実装がどこにあるか

実装を調べようにも SessionMiddlewareMIDDLEWARE_CLASSES で読み込むよう定義しているだけ。なので、 MIDDLEWARE_CLASSES そのものを検索する。すると、 django.core.handlers.base でなにか処理していることがわかる。

django/base.py at master · django/django · GitHub

BaseHandler

BaseHandler クラスでやってることの大枠はたぶんこう

  • init
  • load_middleware
  • get_response

初期化時に process_xxxメソッドに対応する変数を初期化しておく。 継承先の __call__ で呼ばれる load_middlewareMIDDLEWARE_CLASSES で定義したミドルウェアを取り出し、ミドルウェアインスタンスの属性に process_xxx があれば追加しておく。 レスポンスを返すときにフックポイントにきたら先ほど登録したミドルウェアを取り出して実行する。

WSGIHandler

先ほどの BaseHandler クラスを使っているのが WSGIHandler__call__ されたらレスポンスを返す。どこかで while True: のようなループがあって、そこでインスタンスになっているものが待ち受けている?

django/wsgi.py at master · django/django · GitHub

使われているところを探すと、 django.core.wsgi#get_wsgi_application で使われていることがわかった。これは django.setup() して return WSGIServer するだけの関数のようだった。これは django-admin.py startproject proj したときに生成される wsgi.py で使われている。gunicorn などで動かすときに使う。

おわりに

  • 文字列で指定したクラスを import する
  • middleware から固定のメソッド名を探して格納、フック時に適用する

というような話だった。

次は余力があれば runserver か render あたりをかく。