Django/runserver時の処理を読む
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[Djangoを読む]]
#contents
*はじめに [#p24a089a]
Djangoプロジェクト(とアプリ)を作成したのでいよいよフレ...
と言ってもいきなりフルセットのアプリを追っかけるのはつら...
チュートリアルの通りに書いていくと以下の3つのファイルを作...
polls/view.py
#code(Python){{
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the poll...
}}
polls/urls.py
#code(Python){{
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
}}
mysite/urls.py
#code(Python){{
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^polls/', include('polls.urls')),
url(r'^admin/', admin.site.urls),
]
}}
で、manage.pyを使って開発サーバを起動と。
$ python manage.py runserver
*django/core/management/commands/runserver.py [#vf0ab17c]
それでは挙げたのとは逆順にサーバ起動から見ていきましょう...
#code(Python){{
def handle(self, *args, **options):
self.run(**options)
}}
runメソッド
#code(Python){{
def run(self, **options):
"""
Runs the server, using the autoreloader if needed
"""
use_reloader = options['use_reloader']
if use_reloader:
autoreload.main(self.inner_run, None, options)
else:
self.inner_run(None, **options)
}}
オートリローダーを使う、使わないの違いはありますがともか...
inner_runもシステムチェックとかをしている部分は飛ばして、...
#code(Python){{
def inner_run(self, *args, **options):
try:
handler = self.get_handler(*args, **options)
run(self.addr, int(self.port), handler,
ipv6=self.use_ipv6, threading=threading)
except socket.error as e:
# 省略
except KeyboardInterrupt:
if shutdown_message:
self.stdout.write(shutdown_message)
sys.exit(0)
}}
get_handlerに進む前に、
またrunが出てきていますが、このrunは先ほどのrunメソッドで...
#code(Python){{
from django.core.servers.basehttp import get_internal_wsg...
}}
と、basehttpに定義されている関数なことがわかります。紛ら...
*django/core/servers/basehttp.py [#cba4c610]
**get_internal_wsgi_application [#a9e99c7c]
では改めてget_handlerメソッドを、と言いたいところですが、...
#code(Python){{
def get_handler(self, *args, **options):
"""
Returns the default WSGI handler for the runner.
"""
return get_internal_wsgi_application()
}}
結局、basehttp.pyに集約されているわけですね。というわけで...
#code(Python){{
def get_internal_wsgi_application():
"""
Loads and returns the WSGI application as configured ...
``settings.WSGI_APPLICATION``. With the default ``sta...
this will be the ``application`` object in ``projectn...
This function, and the ``WSGI_APPLICATION`` setting i...
for Django's internal server (runserver); external WS...
be configured to point to the correct application obj...
If settings.WSGI_APPLICATION is not set (is ``None``)...
whatever ``django.core.wsgi.get_wsgi_application`` re...
"""
from django.conf import settings
app_path = getattr(settings, 'WSGI_APPLICATION')
if app_path is None:
return get_wsgi_application()
try:
return import_string(app_path)
except ImportError as e:
# 省略
}}
飛ばしましたが、前回も出てきたsettings、今度はファイルが...
django/conf/__init__.py
#code(Python){{
class Settings(BaseSettings):
def __init__(self, settings_module):
# update this dict from global settings (but only...
for setting in dir(global_settings):
if setting.isupper():
setattr(self, setting, getattr(global_set...
# store the settings module in case someone later...
self.SETTINGS_MODULE = settings_module
mod = importlib.import_module(self.SETTINGS_MODULE)
self._explicit_settings = set()
for setting in dir(mod):
if setting.isupper():
setting_value = getattr(mod, setting)
setattr(self, setting, setting_value)
self._explicit_settings.add(setting)
}}
わかってる人にはわかってるけど、dirで属性一覧が取得できる...
話を戻して、WSGI_APPLICATIONはプロジェクトフォルダのsetti...
#code(Python){{
WSGI_APPLICATION = 'mysite.wsgi.application'
}}
import_stringはdjango/utils/module_loading.pyに定義されて...
#code(Python){{
"""
WSGI config for mysite project.
It exposes the WSGI callable as a module-level variable n...
For more information on this file, see
https://docs.djangoproject.com/en/1.10/howto/deployment/w...
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.s...
application = get_wsgi_application()
}}
たらいまわしされてる気分ですが、結局、get_wsgi_applicatio...
django/coreの方のwsgi.py
#code(Python){{
import django
from django.core.handlers.wsgi import WSGIHandler
def get_wsgi_application():
"""
The public interface to Django's WSGI support. Should...
callable.
Allows us to avoid making django.core.handlers.WSGIHa...
case the internal WSGI implementation changes or move...
"""
django.setup(set_prefix=False)
return WSGIHandler()
}}
うんざりしてきました。今度は、django/core/handlersのwsgi....
#code(Python){{
class WSGIHandler(base.BaseHandler):
def __init__(self, *args, **kwargs):
super(WSGIHandler, self).__init__(*args, **kwargs)
self.load_middleware()
}}
**BaseHandler.load_middleware [#n3643480]
baseは同じフォルダにあるdjango/core/handlers/base.pyです...
#code(Python){{
def load_middleware(self):
"""
Populate middleware lists from settings.MIDDLEWAR...
MIDDLEWARE_CLASSES).
Must be called after the environment is fixed (se...
"""
self._request_middleware = []
self._view_middleware = []
self._template_response_middleware = []
self._response_middleware = []
self._exception_middleware = []
if settings.MIDDLEWARE is None:
# 省略
else:
handler = convert_exception_to_response(self....
for middleware_path in reversed(settings.MIDD...
middleware = import_string(middleware_path)
try:
mw_instance = middleware(handler)
except MiddlewareNotUsed as exc:
# 省略
continue
if hasattr(mw_instance, 'process_view'):
self._view_middleware.insert(0, mw_in...
if hasattr(mw_instance, 'process_template...
self._template_response_middleware.ap...
if hasattr(mw_instance, 'process_exceptio...
self._exception_middleware.append(mw_...
handler = convert_exception_to_response(m...
# We only assign to this when initialization is c...
# as a flag for initialization being complete.
self._middleware_chain = handler
}}
convert_exception_to_responseは同じフォルダにあるexceptio...
settingsに定義されているミドルウェアを一つずつ構築し、han...
#code(Python){{
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddlew...
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddlewa...
]
}}
reversedしているので、下から先に構築されます。
どれでもいいのでdjango/contrib/sessions/middleware.pyを見...
#code(Python){{
class SessionMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
self.get_response = get_response
engine = import_module(settings.SESSION_ENGINE)
self.SessionStore = engine.SessionStore
def process_request(self, request):
session_key = request.COOKIES.get(settings.SESSIO...
request.session = self.SessionStore(session_key)
def process_response(self, request, response):
# 省略
}}
MiddlewareMixinはdjango/utils/deprecation.pyに定義されて...
#code(Python){{
class MiddlewareMixin(object):
def __init__(self, get_response=None):
self.get_response = get_response
super(MiddlewareMixin, self).__init__()
def __call__(self, request):
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, res...
return response
}}
書いてあるままですが、
+process_requestが定義されてたらそれを呼ぶ
+process_requestが何も返さなかったらコンストラクタで受け...
+process_responseが定義されてたらそれを呼ぶ
ここで、get_responseという名前ですが、これは__call__メソ...
ラップして作られた先頭のミドルウェアの__call__が呼ばれる
次のミドルウェアの__call__が呼ばれる
・・・
BaseHandlerの_get_responseが呼ばれる(これは関数)
のようにミドルウェアが連続実行されていくという仕組みにな...
**run [#i3129093]
さて、話をdjango/core/servers/basehttp.pyに戻して、run関...
#code(Python){{
def run(addr, port, wsgi_handler, ipv6=False, threading=F...
server_address = (addr, port)
if threading:
httpd_cls = type(str('WSGIServer'), (socketserver...
else:
httpd_cls = WSGIServer
httpd = httpd_cls(server_address, WSGIRequestHandler,...
if threading:
# ThreadingMixIn.daemon_threads indicates how thr...
# abrupt shutdown; like quitting the server by th...
# by the auto-reloader. True means the server wil...
# termination before it quits. This will make aut...
# and will prevent the need to kill the server ma...
# isn't terminating correctly.
httpd.daemon_threads = True
httpd.set_app(wsgi_handler)
httpd.serve_forever()
}}
スレッドを使うかどうかの違いはありますが使われるのはWSGIS...
*django/utils/autoreload.py [#f09c4ad7]
最後に、後で見るといったautoloadです。
#code(Python){{
def main(main_func, args=None, kwargs=None):
if args is None:
args = ()
if kwargs is None:
kwargs = {}
if sys.platform.startswith('java'):
reloader = jython_reloader
else:
reloader = python_reloader
wrapped_main_func = check_errors(main_func)
reloader(wrapped_main_func, args, kwargs)
}}
まあCPythonということでpython_reloaderへ。
#code(Python){{
def python_reloader(main_func, args, kwargs):
if os.environ.get("RUN_MAIN") == "true":
thread.start_new_thread(main_func, args, kwargs)
try:
reloader_thread()
except KeyboardInterrupt:
pass
else:
try:
exit_code = restart_with_reloader()
if exit_code < 0:
os.kill(os.getpid(), -exit_code)
else:
sys.exit(exit_code)
except KeyboardInterrupt:
pass
}}
RUN_MAINという謎の環境変数が出てきました。定義されてない...
#code(Python){{
def restart_with_reloader():
while True:
args = [sys.executable] + ['-W%s' % o for o in sy...
if sys.platform == "win32":
args = ['"%s"' % arg for arg in args]
new_environ = os.environ.copy()
new_environ["RUN_MAIN"] = 'true'
exit_code = os.spawnve(os.P_WAIT, sys.executable,...
if exit_code != 3:
return exit_code
}}
RUN_MAIN出てきました。それにしても力技感あふれるコードで...
次にreload_threadを見てみます。
#code(Python){{
def reloader_thread():
ensure_echo_on()
if USE_INOTIFY:
fn = inotify_code_changed
else:
fn = code_changed
while RUN_RELOADER:
change = fn()
if change == FILE_MODIFIED:
sys.exit(3) # force reload
elif change == I18N_MODIFIED:
reset_translations()
time.sleep(1)
}}
これ以上追いかけるのはやめますが、何をやっているかをまと...
+親プロセスはRUN_MAIN環境変数を定義して自分と同じ引数で子...
+子プロセスは元々の関数をスレッドで実行。一方でファイルの...
+ファイルが更新されてたらステータス3で終了
+それを検出した親プロセスは子プロセスを実行し直す→更新し...
なんというか力技ですね:-)
*おわりに [#rc91fc8f]
今回はDjangoテストサーバの起動について見てきました。個々...
Railsバッシングばかりしている気がしますが、次回はリクエス...
終了行:
[[Djangoを読む]]
#contents
*はじめに [#p24a089a]
Djangoプロジェクト(とアプリ)を作成したのでいよいよフレ...
と言ってもいきなりフルセットのアプリを追っかけるのはつら...
チュートリアルの通りに書いていくと以下の3つのファイルを作...
polls/view.py
#code(Python){{
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the poll...
}}
polls/urls.py
#code(Python){{
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
}}
mysite/urls.py
#code(Python){{
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^polls/', include('polls.urls')),
url(r'^admin/', admin.site.urls),
]
}}
で、manage.pyを使って開発サーバを起動と。
$ python manage.py runserver
*django/core/management/commands/runserver.py [#vf0ab17c]
それでは挙げたのとは逆順にサーバ起動から見ていきましょう...
#code(Python){{
def handle(self, *args, **options):
self.run(**options)
}}
runメソッド
#code(Python){{
def run(self, **options):
"""
Runs the server, using the autoreloader if needed
"""
use_reloader = options['use_reloader']
if use_reloader:
autoreload.main(self.inner_run, None, options)
else:
self.inner_run(None, **options)
}}
オートリローダーを使う、使わないの違いはありますがともか...
inner_runもシステムチェックとかをしている部分は飛ばして、...
#code(Python){{
def inner_run(self, *args, **options):
try:
handler = self.get_handler(*args, **options)
run(self.addr, int(self.port), handler,
ipv6=self.use_ipv6, threading=threading)
except socket.error as e:
# 省略
except KeyboardInterrupt:
if shutdown_message:
self.stdout.write(shutdown_message)
sys.exit(0)
}}
get_handlerに進む前に、
またrunが出てきていますが、このrunは先ほどのrunメソッドで...
#code(Python){{
from django.core.servers.basehttp import get_internal_wsg...
}}
と、basehttpに定義されている関数なことがわかります。紛ら...
*django/core/servers/basehttp.py [#cba4c610]
**get_internal_wsgi_application [#a9e99c7c]
では改めてget_handlerメソッドを、と言いたいところですが、...
#code(Python){{
def get_handler(self, *args, **options):
"""
Returns the default WSGI handler for the runner.
"""
return get_internal_wsgi_application()
}}
結局、basehttp.pyに集約されているわけですね。というわけで...
#code(Python){{
def get_internal_wsgi_application():
"""
Loads and returns the WSGI application as configured ...
``settings.WSGI_APPLICATION``. With the default ``sta...
this will be the ``application`` object in ``projectn...
This function, and the ``WSGI_APPLICATION`` setting i...
for Django's internal server (runserver); external WS...
be configured to point to the correct application obj...
If settings.WSGI_APPLICATION is not set (is ``None``)...
whatever ``django.core.wsgi.get_wsgi_application`` re...
"""
from django.conf import settings
app_path = getattr(settings, 'WSGI_APPLICATION')
if app_path is None:
return get_wsgi_application()
try:
return import_string(app_path)
except ImportError as e:
# 省略
}}
飛ばしましたが、前回も出てきたsettings、今度はファイルが...
django/conf/__init__.py
#code(Python){{
class Settings(BaseSettings):
def __init__(self, settings_module):
# update this dict from global settings (but only...
for setting in dir(global_settings):
if setting.isupper():
setattr(self, setting, getattr(global_set...
# store the settings module in case someone later...
self.SETTINGS_MODULE = settings_module
mod = importlib.import_module(self.SETTINGS_MODULE)
self._explicit_settings = set()
for setting in dir(mod):
if setting.isupper():
setting_value = getattr(mod, setting)
setattr(self, setting, setting_value)
self._explicit_settings.add(setting)
}}
わかってる人にはわかってるけど、dirで属性一覧が取得できる...
話を戻して、WSGI_APPLICATIONはプロジェクトフォルダのsetti...
#code(Python){{
WSGI_APPLICATION = 'mysite.wsgi.application'
}}
import_stringはdjango/utils/module_loading.pyに定義されて...
#code(Python){{
"""
WSGI config for mysite project.
It exposes the WSGI callable as a module-level variable n...
For more information on this file, see
https://docs.djangoproject.com/en/1.10/howto/deployment/w...
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.s...
application = get_wsgi_application()
}}
たらいまわしされてる気分ですが、結局、get_wsgi_applicatio...
django/coreの方のwsgi.py
#code(Python){{
import django
from django.core.handlers.wsgi import WSGIHandler
def get_wsgi_application():
"""
The public interface to Django's WSGI support. Should...
callable.
Allows us to avoid making django.core.handlers.WSGIHa...
case the internal WSGI implementation changes or move...
"""
django.setup(set_prefix=False)
return WSGIHandler()
}}
うんざりしてきました。今度は、django/core/handlersのwsgi....
#code(Python){{
class WSGIHandler(base.BaseHandler):
def __init__(self, *args, **kwargs):
super(WSGIHandler, self).__init__(*args, **kwargs)
self.load_middleware()
}}
**BaseHandler.load_middleware [#n3643480]
baseは同じフォルダにあるdjango/core/handlers/base.pyです...
#code(Python){{
def load_middleware(self):
"""
Populate middleware lists from settings.MIDDLEWAR...
MIDDLEWARE_CLASSES).
Must be called after the environment is fixed (se...
"""
self._request_middleware = []
self._view_middleware = []
self._template_response_middleware = []
self._response_middleware = []
self._exception_middleware = []
if settings.MIDDLEWARE is None:
# 省略
else:
handler = convert_exception_to_response(self....
for middleware_path in reversed(settings.MIDD...
middleware = import_string(middleware_path)
try:
mw_instance = middleware(handler)
except MiddlewareNotUsed as exc:
# 省略
continue
if hasattr(mw_instance, 'process_view'):
self._view_middleware.insert(0, mw_in...
if hasattr(mw_instance, 'process_template...
self._template_response_middleware.ap...
if hasattr(mw_instance, 'process_exceptio...
self._exception_middleware.append(mw_...
handler = convert_exception_to_response(m...
# We only assign to this when initialization is c...
# as a flag for initialization being complete.
self._middleware_chain = handler
}}
convert_exception_to_responseは同じフォルダにあるexceptio...
settingsに定義されているミドルウェアを一つずつ構築し、han...
#code(Python){{
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddlew...
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddlewa...
]
}}
reversedしているので、下から先に構築されます。
どれでもいいのでdjango/contrib/sessions/middleware.pyを見...
#code(Python){{
class SessionMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
self.get_response = get_response
engine = import_module(settings.SESSION_ENGINE)
self.SessionStore = engine.SessionStore
def process_request(self, request):
session_key = request.COOKIES.get(settings.SESSIO...
request.session = self.SessionStore(session_key)
def process_response(self, request, response):
# 省略
}}
MiddlewareMixinはdjango/utils/deprecation.pyに定義されて...
#code(Python){{
class MiddlewareMixin(object):
def __init__(self, get_response=None):
self.get_response = get_response
super(MiddlewareMixin, self).__init__()
def __call__(self, request):
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, res...
return response
}}
書いてあるままですが、
+process_requestが定義されてたらそれを呼ぶ
+process_requestが何も返さなかったらコンストラクタで受け...
+process_responseが定義されてたらそれを呼ぶ
ここで、get_responseという名前ですが、これは__call__メソ...
ラップして作られた先頭のミドルウェアの__call__が呼ばれる
次のミドルウェアの__call__が呼ばれる
・・・
BaseHandlerの_get_responseが呼ばれる(これは関数)
のようにミドルウェアが連続実行されていくという仕組みにな...
**run [#i3129093]
さて、話をdjango/core/servers/basehttp.pyに戻して、run関...
#code(Python){{
def run(addr, port, wsgi_handler, ipv6=False, threading=F...
server_address = (addr, port)
if threading:
httpd_cls = type(str('WSGIServer'), (socketserver...
else:
httpd_cls = WSGIServer
httpd = httpd_cls(server_address, WSGIRequestHandler,...
if threading:
# ThreadingMixIn.daemon_threads indicates how thr...
# abrupt shutdown; like quitting the server by th...
# by the auto-reloader. True means the server wil...
# termination before it quits. This will make aut...
# and will prevent the need to kill the server ma...
# isn't terminating correctly.
httpd.daemon_threads = True
httpd.set_app(wsgi_handler)
httpd.serve_forever()
}}
スレッドを使うかどうかの違いはありますが使われるのはWSGIS...
*django/utils/autoreload.py [#f09c4ad7]
最後に、後で見るといったautoloadです。
#code(Python){{
def main(main_func, args=None, kwargs=None):
if args is None:
args = ()
if kwargs is None:
kwargs = {}
if sys.platform.startswith('java'):
reloader = jython_reloader
else:
reloader = python_reloader
wrapped_main_func = check_errors(main_func)
reloader(wrapped_main_func, args, kwargs)
}}
まあCPythonということでpython_reloaderへ。
#code(Python){{
def python_reloader(main_func, args, kwargs):
if os.environ.get("RUN_MAIN") == "true":
thread.start_new_thread(main_func, args, kwargs)
try:
reloader_thread()
except KeyboardInterrupt:
pass
else:
try:
exit_code = restart_with_reloader()
if exit_code < 0:
os.kill(os.getpid(), -exit_code)
else:
sys.exit(exit_code)
except KeyboardInterrupt:
pass
}}
RUN_MAINという謎の環境変数が出てきました。定義されてない...
#code(Python){{
def restart_with_reloader():
while True:
args = [sys.executable] + ['-W%s' % o for o in sy...
if sys.platform == "win32":
args = ['"%s"' % arg for arg in args]
new_environ = os.environ.copy()
new_environ["RUN_MAIN"] = 'true'
exit_code = os.spawnve(os.P_WAIT, sys.executable,...
if exit_code != 3:
return exit_code
}}
RUN_MAIN出てきました。それにしても力技感あふれるコードで...
次にreload_threadを見てみます。
#code(Python){{
def reloader_thread():
ensure_echo_on()
if USE_INOTIFY:
fn = inotify_code_changed
else:
fn = code_changed
while RUN_RELOADER:
change = fn()
if change == FILE_MODIFIED:
sys.exit(3) # force reload
elif change == I18N_MODIFIED:
reset_translations()
time.sleep(1)
}}
これ以上追いかけるのはやめますが、何をやっているかをまと...
+親プロセスはRUN_MAIN環境変数を定義して自分と同じ引数で子...
+子プロセスは元々の関数をスレッドで実行。一方でファイルの...
+ファイルが更新されてたらステータス3で終了
+それを検出した親プロセスは子プロセスを実行し直す→更新し...
なんというか力技ですね:-)
*おわりに [#rc91fc8f]
今回はDjangoテストサーバの起動について見てきました。個々...
Railsバッシングばかりしている気がしますが、次回はリクエス...
ページ名: