DjangoのWSGIってどうなってるんだ、と思ったので、コード読んだ話です。説明ではありません。自分のための備忘録。
- 最初は、wsgi.py
- django.core.wsgi.get_wsgi_application
- django.setup
- django.utils.log.configure_logging は何?
- django.urls.set_script_prefix ってなんだろ?
- django.apps.apps.populateってなんだろう?
- django.core.handlers.wsgi.WSGIHandler とはなんぞや。
- base.BaseHandler ?
- request_class=WSGIRequest と言うプロパティ
- WSGIRequest ってなんだろう
- HttpRequest クラスを継承してる。これは何?
- 終わり
Djangoのバージョンは、2.0.5。
最初は、wsgi.py
myproject/wsgi.py
から読み進める。
from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings") application = get_wsgi_application()
とりあえず、applicationが呼ばれると思うので、get_wsgi_application()
の中を読んでいく。
django.core.wsgi.get_wsgi_application
def get_wsgi_application(): """ The public interface to Django's WSGI support. Return a WSGI callable. Avoids making django.core.handlers.WSGIHandler a public API, in case the internal WSGI implementation changes or moves in the future. """ django.setup(set_prefix=False) return WSGIHandler()
get_wsgi_application()
では、django.core.handlers.wsgi.WSGIHandler
の呼び出し結果を返してる。django.setup(set_prefix=False)
と言う処理も読んでいる。これは、なんだろう。読んでみよう。
django.setup
def setup(set_prefix=True): """ Configure the settings (this happens as a side effect of accessing the first setting), configure logging and populate the app registry. Set the thread-local urlresolvers script prefix if `set_prefix` is True. """ from django.apps import apps from django.conf import settings from django.urls import set_script_prefix from django.utils.log import configure_logging configure_logging(settings.LOGGING_CONFIG, settings.LOGGING) if set_prefix: set_script_prefix( '/' if settings.FORCE_SCRIPT_NAME is None else settings.FORCE_SCRIPT_NAME ) apps.populate(settings.INSTALLED_APPS)
疑問が出た。
django.utils.log.configure_logging
と言うロギングっぽい設定をしている。これは何の設定?django.urls.set_script_prefix
ってなんだろ?django.apps.apps.populate
ってなんだろう?
django.utils.log.configure_logging
は何?
def configure_logging(logging_config, logging_settings): if logging_config: # First find the logging configuration function ... logging_config_func = import_string(logging_config) logging.config.dictConfig(DEFAULT_LOGGING) # ... then invoke it with the logging settings if logging_settings: logging_config_func(logging_settings)
- ロギングの設定があったら、ロギングの設定を読み込んでる。
- デフォルトのロギング設定も書いてあった。
- いい感じに、文字列からモジュールをインポートしてる様子。
django.urls.set_script_prefix
ってなんだろ?
def set_script_prefix(prefix): """ Set the script prefix for the current thread. """ if not prefix.endswith('/'): prefix += '/' _prefixes.value = prefix
_prefixes
って変数にプリフィックスを入れてる。
これは何だろ、と思ったらこんな感じに定義されてる。
from threading import local ... _prefixes = local()
スレッドローカルなデータ。マルチスレッドにする時に使うのかな。あとで、調べる。 よくわかってないけど進む。
django.apps.apps.populate
ってなんだろう?
https://github.com/django/django/blob/2.0.5/django/apps/registry.py#L59
settings.INSTALLED_APPS
に書いてあるアプリを上から読み込んで有効化してる。- 有効化する時に重複しないようにロックを取得してる。
重複して読み込まないようにチェックしてる。(重複して読み込むケースがあるんだろうか?)
以下の処理が気になる。各アプリのコンフィグと親アプリを相互参照できるようにリンクしてる。なるほど
- 他の箇所で、全てのモデルを取得して、キャッシュをクリアするとかできるようになってる。へえ。
django.apps
はdjangoにインストールされているアプリ群を管理するアプリのイメージ
self.app_configs[app_config.label] = app_config app_config.apps = self
django.core.handlers.wsgi.WSGIHandler
とはなんぞや。
最初に戻って django.core.handlers.wsgi.WSGIHandler
はなんだろう。
https://github.com/django/django/blob/2.0.5/django/core/handlers/wsgi.py#L135
base.BaseHandler
を継承している.request_class=WSGIRequest
と言うプロパティを持ってる。__init__
と__call__
がメソッドとして定義されてるクラス。
base.BaseHandler
?
https://github.com/django/django/blob/2.0.5/django/core/handlers/base.py#L15
- ミドルウェアを読み込むメソッドがある。
- atomic_requestを設定してるメソッドがある
- レスポンスを返すメソッドがある
- Djangoのアプリのミドルウェアのチェーンを実行していくクラスっぽい。
request_class=WSGIRequest
と言うプロパティ
request_class
はどこで読まれるんだろう、と思ったら、base.BaseHandler
では読み込まれない。- 読み込まれるのは、
WSGIHandler.__call__
の中。クラス変数になってるので拡張ポイントっぽい。 https://github.com/django/django/blob/2.0.5/django/core/handlers/wsgi.py#L145 WSGIRequest
ってなんだろう
WSGIRequest
ってなんだろう
https://github.com/django/django/blob/2.0.5/django/core/handlers/wsgi.py#L66
HttpRequest
クラスを継承してる。これは何?- 初期化処理の中で、環境の設定を読み込んでいる様子。
- HTTPリクエストに設定されてる環境のヘッダーとかをDjangoのフォーマットに直している。
- それを、WSGIHandlerがDjangoのミドルウェアチェーンに渡して、responseを作る。
HttpRequest
クラスを継承してる。これは何?
https://github.com/django/django/blob/2.0.5/django/http/request.py#L37
- HttpRequestのベースになる情報を整理するところ。
- WSGIRequestの場合は、WSGIHandler経由で渡ってきたenvironの情報を設定してほげほげしてる。
終わり
- 何と無く雰囲気がわかった。
- WSGIアプリのWebサーバ
gunicorn
とかは、多分environとかをいい感じに渡しながらマルチプロセスにして管理してくれるのかな、と思った。 - そのうち
gunicorn
とかuWsgi
のコードも読みたい。
よかったら、アンケートに答えてもらえると嬉しいです。