WSGIからの流れを大まかに掴めたのでまとめたい。
かなり大まかには、この画像を念頭におけばいいと思う。
今回はDjango1.4を対象にしている。
DjangoのView
まず簡単に触れておきたいのがDjangoのView。
Viewとは
- リクエストを受け取る
- レスポンスを返す
- 呼び出し可能である
オブジェクトのことで、このViewがリクエスト->レスポンスの末端となっている。
冒頭の図がわかりやすいと思う。
あとはチュートリアル。
はじめてのビュー作成
クラスベースビューの場合、流れが複雑になるからそれはそれで別の機会にまとめたい。
https://github.com/django/django/blob/1.4/django/views/generic/base.py#L11
Djangoのhandler
Djangoの流れを理解するにはhandlerを読むと(・∀・)イイ!!
https://github.com/django/django/blob/1.4/django/core/handlers/base.py
BaseHandlerクラスのget_response()メソッドが流れの肝になる。
このメソッドはリクエストを受けとってレスポンスを返している。
handlerがしているのは
こんなところ。
適切なViewにリクエストを渡す
適切なViewにリクエストを渡すってのがURLDispatcherとかそのあたり。
https://github.com/django/django/blob/1.4/django/core/handlers/base.py#L98
このへん読めばいい。
実際にViewが呼び出されているのはここ。
https://github.com/django/django/blob/1.4/django/core/handlers/base.py#L111
Viewから返ってきたレスポンスのレンダリングを呼び出す
冒頭の図では、ビューからのレスポンスの矢印にTemplateが突き刺さってるけど、
あれはhandlerによって「あのへん」でTemplateがレンダリングされているからそう書いた。
具体的にはここ
https://github.com/django/django/blob/1.4/django/core/handlers/base.py#L136
強調したいのが、「View内ではTemplateのレンダリングが行われていない」ということ。
Viewはあくまで表示させたいデータを選択、提示しているのであって、表現はおこなっていない。
表現を担当しているのはTemplateであり、それがレンダリングされるのはhandlerのなか。
これはDjangoのルースカップリングの思想があるからこそ。
間でミドルウェアを呼び出す
まぁ読めばわかるけど、例えばrequest_middlewareが呼ばれてるのはここ。
https://github.com/django/django/blob/1.4/django/core/handlers/base.py#L88
たしかにViewの呼び出しの前にあるね。
WSGIHandler
んーでもってこのhandlerをWSGI対応させたのがWSGIHandler
https://github.com/django/django/blob/1.4/django/core/handlers/wsgi.py
そもそもWSGIって何よ。
WSGIとは
WebサーバとWebアプリケーションをつなげるインタフェースです。
http://ja.wikipedia.org/wiki/Web_Server_Gateway_Interface
だいたいはこれを読めばいい。
ここで言いたいのは、アプリケーション側が提供するのは呼び出し可能オブジェクトであればいいということ。
このオブジェクト(注: アプリケーション側が提供するオブジェクトのこと) が呼び出される際、引数 environ としてCGIと同じ環境変数が渡され、引数 start_response として、ステータスコードとレスポンスヘッダを受け取る呼び出し可能オブジェクトが渡される。
とのこと。
そんでもって
WSGIアプリケーションの戻り値は、本文を生成するイテレート可能なオブジェクトである必要がある。
結果はiteratableなオブジェクトを返せば良い、と。
WSGIHandlerを読む
__call__()読めばいいね。
def __call__(self, environ, start_response):
たしかに environ と start_response を受け取ってる。
んでレスポンスを返してる。レスポンスというのはHttpResponseとかそのへんだろう。
(後述するけど、WSGIの仕様から言ってHttpResponseはiteratableなはず)
WSGIHandlerの入り口
エントリーポイントはここになってる。
https://github.com/django/django/blob/1.4/django/core/wsgi.py
まぁこれがプロジェクト配下のwsgi.pyから呼ばれるというわけ
https://github.com/django/django/blob/1.4/django/conf/project_template/project_name/wsgi.py
ちょっとWSGIの実装読もうか
http://hg.python.org/cpython/file/3f739f42be51/Lib/wsgiref/handlers.py
BaseHandlerクラスを読めばいい。
run() の中でアプリケーションが走り始めてるのが分かる。
アプリケーション側から返される『self.result』。
これはwrite()で使われているよう。
このwrite()によってサーバー側へコンテンツを返してるっぽい(まだちゃんと読んでない)。
(アプリケーションからの結果をStringIO的にφ(`д´)カキカキしてるんだろう)
HttpResponseとWSGI
self.resultはiteratableでないといけない、これはWSGIの仕様といった。
self.resultはDjangoのHttpResponseであるわけで、こいつは __iter__()でコンテンツを返すと予想できる。
読んでみる。
HttpResponseはこれ。
https://github.com/django/django/blob/1.4/django/http/__init__.py#L559
__iter__()はここに。
https://github.com/django/django/blob/1.4/django/http/__init__.py#L705
def __iter__(self): self._iterator = iter(self._container) return self
self._containerというのをイテレータで返している。
self._containerについてはself.contentをみれば大体分かる
@content.setter def content(self, value): if hasattr(value, '__iter__') and not isinstance(value, (bytes, six.string_types)): self._container = value self._base_content_is_iter = True else: self._container = [value] self._base_content_is_iter = False
content -> _conteiner -> __iter__ -> wsgiref.base.BaseHandler.result
といった流れ。