runserver がどう動いているか実装をみる

いつも開発で使うことになる runserver 。これはどういう風にしてうごいているのかを確認してみる。あと、 middleware がどう動くか実装をみる - そのあれ でかいた BaseHandler がどこで挿入されているか確認する。

参考

おさらい

実行するコマンドはこういうやつ

python manage.py runserver
python manage.py runserver 0.0.0.0:8000
python manage.py runserver 0.0.0.0:8001 --settings=proj.settings

実行コマンドをみる

読むモジュールは django 標準で登録されているので django.core.management.commands.runserver

BaseCommand.handle が起点になるのは manage.py(django-admin.py)でコマンドを実行するための実装を見る - そのあれ で確認したとおり。

流れ

  • self.handle
  • self.run
  • self.inner_run
    • self.validate
    • self.check_migrations
    • self.get_handler
      • get_internal_application
    • run

BaseHandler がつかわれているところ

get_internal_application ではこういう実装になっている(ちょっと端折っている)。

app_path = getattr(settings, 'WSGI_APPLICATION')
if app_path is None:
    return get_wsgi_application()

try:
    return import_string(app_path)

docstring にかいてあるのだけど、 settings に WSGI_APPLICATION を指定していなければ get_wsgi_application が呼ばれるので、前回書いた内容通りの WSGIHandler が使われる。settings の WSGI_APPLICATION でのデフォルトは proj.wsgi.application という風に生成されている。実際 wsgi.py では application = get_wsgi_application() としてモジュール変数にアサインしている。

ちょっと誤解していたので訂正。

  • settings に WSGI_APPLICATION を指定していなければ get_wsgi_application が呼ばれるので、前回書いたとおり WSGIHandler が使われる
  • settings の WSGI_APPLICATION のデフォルト値は proj.wsgi.application という風に生成されている

    • wsgi.py では application = get_wsgi_application() としてモジュール変数にアサインしている。
    • = WSGIHandler が使われる

つまり初期設定だとどちらでも WSGIHandler が使われるということだった。

自分の理解が正しければ、このあたりまできたら次は WSGI application を動かすってどういうことなのかってところに行きそうなんだけど。そこまでわかってないのでまた今度。

メインループがなにをしているかをみる

読むモジュールは django.cre.servers.basehttpWSGIServer.run メソッドをみる。

WSGIServer の生成

threading が有効であれば socketserver.ThreadingMixIn を Mixin する様子。無効なら WSGIServer のみつかう。

この WSGIServerdjango.core.servers.basehhtp モジュールのクラス。抜粋してはるとこう

class WSGIServer(simple_server.WSGIServer, object):
    """BaseHTTPServer that implements the Python WSGI protocol"""

    request_queue_size = 10

    def __init__(self, *args, **kwargs):
        if kwargs.pop('ipv6', False):
            self.address_family = socket.AF_INET6
        super(WSGIServer, self).__init__(*args, **kwargs)

wsgiref.simple_serverWSGIServer を呼び出している。

ここをもう少しみていくとこういう継承になっている。

  • django.core.servers.basehttp#WSGIServer
  • wsgiref.simple_server#WSGIServer
  • http.server#HTTPServer
  • socketserver#TCPServer

つまり django -> wsgiref -> HTTPServer -> socket 通信レイヤーの TCPServer まで降りて行くことになる。

WSGIserver の実行

おわりに

前に開発用サーバーを動かすというときに、たしかに Django が用意してくれたコマンドのサーバーがあるけど、なにをどこまでやっているかがわからなかった。このライブラリではどのレイヤーまで面倒をみてくれるかというのを知るとなにかと楽になる。