Django/リクエストの処理を読む
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[Djangoを読む]]
#contents
*はじめに [#j2fb036b]
前回はサーバが起動するまでを見てきました。それでは続いて...
*django/core/servers/basehttp.py [#g9a8f1a5]
見るのは引き続き、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()
}}
**WSGIServer [#y3301245]
WSGIServerは標準ライブラリに用意されているクラスでwsgi.si...
WSGIServerはhttp.serverのHTTPServerを継承し、HTTPServerは...
#code(Python){{
def serve_forever(self, poll_interval=0.5):
"""Handle one request at a time until shutdown.
Polls for shutdown every poll_interval seconds. Ignores
self.timeout. If you need to do periodic tasks, do th...
another thread.
"""
self.__is_shut_down.clear()
try:
# XXX: Consider using another file descriptor or ...
# socket to wake this up instead of polling. Poll...
# responsiveness to a shutdown request and wastes...
# times.
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)
while not self.__shutdown_request:
ready = selector.select(poll_interval)
if ready:
self._handle_request_noblock()
self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
}}
selectorとなっているのはselectorsモジュールで定義されてい...
_handle_request_noblock。get_requestはTCPなのかUDPなのか...
#code(Python){{
def _handle_request_noblock(self):
"""Handle one request, without blocking.
I assume that selector.select() has returned that the...
readable before this function was called, so there sh...
blocking in get_request().
"""
try:
request, client_address = self.get_request()
except OSError:
return
if self.verify_request(request, client_address):
try:
self.process_request(request, client_address)
except:
self.handle_error(request, client_address)
self.shutdown_request(request)
}}
process_requestおよびprocess_requestから呼び出されるfinis...
#code(Python){{
def process_request(self, request, client_address):
"""Call finish_request.
Overridden by ForkingMixIn and ThreadingMixIn.
"""
self.finish_request(request, client_address)
self.shutdown_request(request)
def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandler...
self.RequestHandlerClass(request, client_address, self)
}}
というわけで、インスタンス作成時に渡したリクエストハンド...
**WSGIRequestHandler [#o4ce23d6]
リクエストハンドラクラスはbasehttp.pyで定義されているWSGI...
#code(Python){{
def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish()
}}
handleメソッドはWSGIRequestHandlerに定義されています。par...
#code(Python){{
def handle(self):
"""Copy of WSGIRequestHandler, but with different Ser...
self.raw_requestline = self.rfile.readline(65537)
if len(self.raw_requestline) > 65536:
self.requestline = ''
self.request_version = ''
self.command = ''
self.send_error(414)
return
if not self.parse_request(): # An error code has bee...
return
handler = ServerHandler(
self.rfile, self.wfile, self.get_stderr(), self.g...
)
handler.request_handler = self # backpointer for...
handler.run(self.server.get_app())
}}
**ServerHandler [#qd5f6d43]
コメントにあるようにServerHandlerとしてbasehttp.pyで定義...
#code(Python){{
def run(self, application):
"""Invoke the application"""
# Note to self: don't move the close()! Asynchronous...
# call close() from finish_response(), so if you clos...
# the double-error branch here, you'll break asynchro...
# prematurely closing. Async servers must return fro...
# closing if there might still be output to iterate o...
try:
self.setup_environ()
self.result = application(self.environ, self.star...
self.finish_response()
except:
try:
self.handle_error()
except:
# If we get an error handling an error, just ...
self.close()
raise # ...and let the actual server figure...
}}
applicationは前回どのように作られているのかを追いかけたWS...
*django/core/handlers/wsgi.py [#mdc18df2]
Djangoのコードに戻ってきました。というわけでWSGIHandlerの...
#code(Python){{
def __call__(self, environ, start_response):
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, e...
try:
request = self.request_class(environ)
except UnicodeDecodeError:
# 省略
response = http.HttpResponseBadRequest()
else:
response = self.get_response(request)
response._handler_class = self.__class__
status = '%d %s' % (response.status_code, response.re...
response_headers = [(str(k), str(v)) for k, v in resp...
for c in response.cookies.values():
response_headers.append((str('Set-Cookie'), str(c...
start_response(force_str(status), response_headers)
if getattr(response, 'file_to_stream', None) is not N...
response = environ['wsgi.file_wrapper'](response....
return response
}}
request_classはすぐ上にありますがWSGIRequestです。respons...
**環境変数設定の確認 [#i2e20a95]
先に進む前に環境変数(実際にはOSの環境変数ではなく辞書オ...
wsgiref.simple_server.WSGIServer.sever_bind
→setup_environ
base_environを設定
http.server.BaseHTTPRequestHandler.parse_request
環境変数ではないがリクエストのパスなどを設定
wsgiref.simple_server.WSGIRequestHandler.get_environ
serverのbase_environをコピー
parse_requestの結果などを環境変数に設定
wsgiref.handlers.BaseHandler.setup_environ
OSの環境変数を読み込み
add_cgi_varsメソッド呼び出し
→SimpleHandlerでオーバーライドされていて引数で渡された...
これらがリクエストを処理する際に設定されている環境変数の...
**get_response [#vc6f37cb]
さて、リクエストが処理される際の環境設定について確認でき...
get_responseメソッドはdjango/core/handlers/base.pyの方のB...
#code(Python){{
def get_response(self, request):
"""Return an HttpResponse object for the given HttpRe...
# Setup default url resolver for this thread
set_urlconf(settings.ROOT_URLCONF)
response = self._middleware_chain(request)
# This block is only needed for legacy MIDDLEWARE_CLA...
# MIDDLEWARE is used, self._response_middleware will ...
# ということらしいので省略
response._closable_objects.append(request)
# If the exception handler returns a TemplateResponse...
# been rendered, force it to be rendered.
if not getattr(response, 'is_rendered', True) and cal...
response = response.render()
if response.status_code == 404:
logger.warning(
'Not Found: %s', request.path,
extra={'status_code': 404, 'request': request},
)
return response
}}
_middleware_chainは前回見たsettingsに基づくミドルウェアの...
**_get_responseその1 [#v05f93ea]
_get_responseは長いのでまず前半。
#code(Python){{
def _get_response(self, request):
"""
Resolve and call the view, then apply view, exception...
template_response middleware. This method is everythi...
inside the request/response middleware.
"""
response = None
if hasattr(request, 'urlconf'):
urlconf = request.urlconf
set_urlconf(urlconf)
resolver = get_resolver(urlconf)
else:
resolver = get_resolver()
resolver_match = resolver.resolve(request.path_info)
callback, callback_args, callback_kwargs = resolver_m...
request.resolver_match = resolver_match
}}
urlconfは設定されていないはずなので引数なしでget_resolver...
#code(Python){{
def get_resolver(urlconf=None):
if urlconf is None:
from django.conf import settings
urlconf = settings.ROOT_URLCONF
return RegexURLResolver(r'^/', urlconf)
}}
**リクエストに対する処理関数の決定(基本構造) [#m868c871]
RegexURLResolverのresolveメソッド。
#code(Python){{
def resolve(self, path):
path = force_text(path) # path may be a reverse_lazy...
tried = []
match = self.regex.search(path)
if match:
new_path = path[match.end():]
for pattern in self.url_patterns:
try:
sub_match = pattern.resolve(new_path)
except Resolver404 as e:
# 省略
else:
if sub_match:
# Merge captured arguments in match w...
sub_match_dict = dict(match.groupdict...
sub_match_dict.update(sub_match.kwargs)
# If there are *any* named groups, ig...
# Otherwise, pass all non-named argum...
sub_match_args = sub_match.args
if not sub_match_dict:
sub_match_args = match.groups() +...
return ResolverMatch(
sub_match.func,
sub_match_args,
sub_match_dict,
sub_match.url_name,
[self.app_name] + sub_match.app_n...
[self.namespace] + sub_match.name...
)
tried.append([pattern])
raise Resolver404({'tried': tried, 'path': new_pa...
raise Resolver404({'path': path})
}}
初めの方は問題ないと思います。
#code(Python){{
def resolve(self, path):
path = force_text(path) # path may be a reverse_lazy...
tried = []
match = self.regex.search(path)
if match:
new_path = path[match.end():]
}}
regexはさっき設定していたr'^/'なんだろうなと想像できます...
#code(Python){{
for pattern in self.url_patterns:
try:
sub_match = pattern.resolve(new_path)
}}
url_patternsなんていつの間に設定されたんや。答えはresolve...
#code(Python){{
@cached_property
def url_patterns(self):
# urlconf_module might be a valid set of patterns, so...
patterns = getattr(self.urlconf_module, "urlpatterns"...
try:
iter(patterns)
except TypeError:
# 省略
return patterns
@cached_property
def urlconf_module(self):
if isinstance(self.urlconf_name, six.string_types):
return import_module(self.urlconf_name)
else:
return self.urlconf_name
}}
というわけで、url_patternsの実体はメソッドでプロパティと...
**urls.pyの読み込み [#ga9e4ac1]
mysite/urls.pyはチュートリアルでは以下のように定義しまし...
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),
]
}}
url、また、includeを追っかける必要があります。それぞれ、d...
includeは長いので今回関係のあるところだけ抜き出すと、
#code(Python){{
def include(arg, namespace=None, app_name=None):
if isinstance(arg, tuple):
# 省略
else:
# No namespace hint - use manually provided names...
urlconf_module = arg
if isinstance(urlconf_module, six.string_types):
urlconf_module = import_module(urlconf_module)
patterns = getattr(urlconf_module, 'urlpatterns', url...
return (urlconf_module, app_name, namespace)
}}
ということで指定されたモジュール(polls.urls)を読み込ん...
#code(Python){{
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
}}
で、url関数。
#code(Python){{
def url(regex, view, kwargs=None, name=None):
if isinstance(view, (list, tuple)):
# For include(...) processing.
urlconf_module, app_name, namespace = view
return RegexURLResolver(regex, urlconf_module, kw...
elif callable(view):
return RegexURLPattern(regex, view, kwargs, name)
else:
raise TypeError('view must be a callable or a lis...
}}
view(第2引数)がタプルなのかcallableなのかによって返すオ...
さて、というわけで以上をまとめると、resolverというのは実...
RegexURLResolver(r'^/')
RegexURLResolver(r'^polls/') # mysite/urls.py
RegexURLPattern(r'^$', views.index) # polls/urls.py
これがわかるとresolveメソッドの動きが理解できるようになり...
**リクエストに対する処理関数の決定(具体例) [#k50badb4]
というわけで、get_resolver関数が返したRegexURLResolverのr...
#code(Python){{
for pattern in self.url_patterns:
try:
sub_match = pattern.resolve(new_path)
}}
と書いてあると、RegexURLResolverオブジェクト(r'polls/')...
#code(Python){{
class RegexURLPattern(LocaleRegexProvider):
def resolve(self, path):
match = self.regex.search(path)
if match:
# If there are any named groups, use those as...
# non-named groups. Otherwise, pass all non-n...
# positional arguments.
kwargs = match.groupdict()
args = () if kwargs else match.groups()
# In both cases, pass any extra_kwargs as **k...
kwargs.update(self.default_args)
return ResolverMatch(self.callback, args, kwa...
}}
で、それをRegexURLResolverのresolveメソッドが受け取り、自...
#code(Python){{
# Merge captured arguments in match with submatch
sub_match_dict = dict(match.groupdict(), **self.default_k...
sub_match_dict.update(sub_match.kwargs)
# If there are *any* named groups, ignore all non-named g...
# Otherwise, pass all non-named arguments as positional a...
sub_match_args = sub_match.args
if not sub_match_dict:
sub_match_args = match.groups() + sub_match.args
return ResolverMatch(
sub_match.func,
sub_match_args,
sub_match_dict,
sub_match.url_name,
[self.app_name] + sub_match.app_names,
[self.namespace] + sub_match.namespaces,
)
}}
これでようやく、リクエストパスに対する処理関数が取得でき...
**_get_responseその2 [#k8abb6a9]
というわけで_get_responseの続き。
#code(Python){{
# Apply view middleware
for middleware_method in self._view_middleware:
response = middleware_method(request, callback, c...
if response:
break
if response is None:
wrapped_callback = self.make_view_atomic(callback)
try:
response = wrapped_callback(request, *callbac...
except Exception as e:
response = self.process_exception_by_middlewa...
# Complain if the view returned None (a common error).
if response is None:
# 省略
# If the response supports deferred rendering, apply ...
# response middleware and then render the response
elif hasattr(response, 'render') and callable(respons...
for middleware_method in self._template_response_...
response = middleware_method(request, response)
# Complain if the template response middlewar...
if response is None:
# 省略
try:
response = response.render()
except Exception as e:
response = self.process_exception_by_middlewa...
return response
}}
make_view_atomicメソッドで何やらDB関連の処理をしています...
#code(Python){{
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the poll...
}}
HttpResponseにはrenderは定義されてません。きっとテンプレ...
*おわりに [#k540d554]
今回は標準モジュールのコード、Djangoのコード、自分の書い...
また、プロパティが使われていたり、オブジェクト構造が動的...
あ、convert_exception_to_response忘れた。もうかなり長くな...
-元々の関数を呼び出して例外(404とかもDjango的には例外と...
-resolverを呼び出してステータスコードに対応するエラーハン...
終了行:
[[Djangoを読む]]
#contents
*はじめに [#j2fb036b]
前回はサーバが起動するまでを見てきました。それでは続いて...
*django/core/servers/basehttp.py [#g9a8f1a5]
見るのは引き続き、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()
}}
**WSGIServer [#y3301245]
WSGIServerは標準ライブラリに用意されているクラスでwsgi.si...
WSGIServerはhttp.serverのHTTPServerを継承し、HTTPServerは...
#code(Python){{
def serve_forever(self, poll_interval=0.5):
"""Handle one request at a time until shutdown.
Polls for shutdown every poll_interval seconds. Ignores
self.timeout. If you need to do periodic tasks, do th...
another thread.
"""
self.__is_shut_down.clear()
try:
# XXX: Consider using another file descriptor or ...
# socket to wake this up instead of polling. Poll...
# responsiveness to a shutdown request and wastes...
# times.
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)
while not self.__shutdown_request:
ready = selector.select(poll_interval)
if ready:
self._handle_request_noblock()
self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
}}
selectorとなっているのはselectorsモジュールで定義されてい...
_handle_request_noblock。get_requestはTCPなのかUDPなのか...
#code(Python){{
def _handle_request_noblock(self):
"""Handle one request, without blocking.
I assume that selector.select() has returned that the...
readable before this function was called, so there sh...
blocking in get_request().
"""
try:
request, client_address = self.get_request()
except OSError:
return
if self.verify_request(request, client_address):
try:
self.process_request(request, client_address)
except:
self.handle_error(request, client_address)
self.shutdown_request(request)
}}
process_requestおよびprocess_requestから呼び出されるfinis...
#code(Python){{
def process_request(self, request, client_address):
"""Call finish_request.
Overridden by ForkingMixIn and ThreadingMixIn.
"""
self.finish_request(request, client_address)
self.shutdown_request(request)
def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandler...
self.RequestHandlerClass(request, client_address, self)
}}
というわけで、インスタンス作成時に渡したリクエストハンド...
**WSGIRequestHandler [#o4ce23d6]
リクエストハンドラクラスはbasehttp.pyで定義されているWSGI...
#code(Python){{
def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish()
}}
handleメソッドはWSGIRequestHandlerに定義されています。par...
#code(Python){{
def handle(self):
"""Copy of WSGIRequestHandler, but with different Ser...
self.raw_requestline = self.rfile.readline(65537)
if len(self.raw_requestline) > 65536:
self.requestline = ''
self.request_version = ''
self.command = ''
self.send_error(414)
return
if not self.parse_request(): # An error code has bee...
return
handler = ServerHandler(
self.rfile, self.wfile, self.get_stderr(), self.g...
)
handler.request_handler = self # backpointer for...
handler.run(self.server.get_app())
}}
**ServerHandler [#qd5f6d43]
コメントにあるようにServerHandlerとしてbasehttp.pyで定義...
#code(Python){{
def run(self, application):
"""Invoke the application"""
# Note to self: don't move the close()! Asynchronous...
# call close() from finish_response(), so if you clos...
# the double-error branch here, you'll break asynchro...
# prematurely closing. Async servers must return fro...
# closing if there might still be output to iterate o...
try:
self.setup_environ()
self.result = application(self.environ, self.star...
self.finish_response()
except:
try:
self.handle_error()
except:
# If we get an error handling an error, just ...
self.close()
raise # ...and let the actual server figure...
}}
applicationは前回どのように作られているのかを追いかけたWS...
*django/core/handlers/wsgi.py [#mdc18df2]
Djangoのコードに戻ってきました。というわけでWSGIHandlerの...
#code(Python){{
def __call__(self, environ, start_response):
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, e...
try:
request = self.request_class(environ)
except UnicodeDecodeError:
# 省略
response = http.HttpResponseBadRequest()
else:
response = self.get_response(request)
response._handler_class = self.__class__
status = '%d %s' % (response.status_code, response.re...
response_headers = [(str(k), str(v)) for k, v in resp...
for c in response.cookies.values():
response_headers.append((str('Set-Cookie'), str(c...
start_response(force_str(status), response_headers)
if getattr(response, 'file_to_stream', None) is not N...
response = environ['wsgi.file_wrapper'](response....
return response
}}
request_classはすぐ上にありますがWSGIRequestです。respons...
**環境変数設定の確認 [#i2e20a95]
先に進む前に環境変数(実際にはOSの環境変数ではなく辞書オ...
wsgiref.simple_server.WSGIServer.sever_bind
→setup_environ
base_environを設定
http.server.BaseHTTPRequestHandler.parse_request
環境変数ではないがリクエストのパスなどを設定
wsgiref.simple_server.WSGIRequestHandler.get_environ
serverのbase_environをコピー
parse_requestの結果などを環境変数に設定
wsgiref.handlers.BaseHandler.setup_environ
OSの環境変数を読み込み
add_cgi_varsメソッド呼び出し
→SimpleHandlerでオーバーライドされていて引数で渡された...
これらがリクエストを処理する際に設定されている環境変数の...
**get_response [#vc6f37cb]
さて、リクエストが処理される際の環境設定について確認でき...
get_responseメソッドはdjango/core/handlers/base.pyの方のB...
#code(Python){{
def get_response(self, request):
"""Return an HttpResponse object for the given HttpRe...
# Setup default url resolver for this thread
set_urlconf(settings.ROOT_URLCONF)
response = self._middleware_chain(request)
# This block is only needed for legacy MIDDLEWARE_CLA...
# MIDDLEWARE is used, self._response_middleware will ...
# ということらしいので省略
response._closable_objects.append(request)
# If the exception handler returns a TemplateResponse...
# been rendered, force it to be rendered.
if not getattr(response, 'is_rendered', True) and cal...
response = response.render()
if response.status_code == 404:
logger.warning(
'Not Found: %s', request.path,
extra={'status_code': 404, 'request': request},
)
return response
}}
_middleware_chainは前回見たsettingsに基づくミドルウェアの...
**_get_responseその1 [#v05f93ea]
_get_responseは長いのでまず前半。
#code(Python){{
def _get_response(self, request):
"""
Resolve and call the view, then apply view, exception...
template_response middleware. This method is everythi...
inside the request/response middleware.
"""
response = None
if hasattr(request, 'urlconf'):
urlconf = request.urlconf
set_urlconf(urlconf)
resolver = get_resolver(urlconf)
else:
resolver = get_resolver()
resolver_match = resolver.resolve(request.path_info)
callback, callback_args, callback_kwargs = resolver_m...
request.resolver_match = resolver_match
}}
urlconfは設定されていないはずなので引数なしでget_resolver...
#code(Python){{
def get_resolver(urlconf=None):
if urlconf is None:
from django.conf import settings
urlconf = settings.ROOT_URLCONF
return RegexURLResolver(r'^/', urlconf)
}}
**リクエストに対する処理関数の決定(基本構造) [#m868c871]
RegexURLResolverのresolveメソッド。
#code(Python){{
def resolve(self, path):
path = force_text(path) # path may be a reverse_lazy...
tried = []
match = self.regex.search(path)
if match:
new_path = path[match.end():]
for pattern in self.url_patterns:
try:
sub_match = pattern.resolve(new_path)
except Resolver404 as e:
# 省略
else:
if sub_match:
# Merge captured arguments in match w...
sub_match_dict = dict(match.groupdict...
sub_match_dict.update(sub_match.kwargs)
# If there are *any* named groups, ig...
# Otherwise, pass all non-named argum...
sub_match_args = sub_match.args
if not sub_match_dict:
sub_match_args = match.groups() +...
return ResolverMatch(
sub_match.func,
sub_match_args,
sub_match_dict,
sub_match.url_name,
[self.app_name] + sub_match.app_n...
[self.namespace] + sub_match.name...
)
tried.append([pattern])
raise Resolver404({'tried': tried, 'path': new_pa...
raise Resolver404({'path': path})
}}
初めの方は問題ないと思います。
#code(Python){{
def resolve(self, path):
path = force_text(path) # path may be a reverse_lazy...
tried = []
match = self.regex.search(path)
if match:
new_path = path[match.end():]
}}
regexはさっき設定していたr'^/'なんだろうなと想像できます...
#code(Python){{
for pattern in self.url_patterns:
try:
sub_match = pattern.resolve(new_path)
}}
url_patternsなんていつの間に設定されたんや。答えはresolve...
#code(Python){{
@cached_property
def url_patterns(self):
# urlconf_module might be a valid set of patterns, so...
patterns = getattr(self.urlconf_module, "urlpatterns"...
try:
iter(patterns)
except TypeError:
# 省略
return patterns
@cached_property
def urlconf_module(self):
if isinstance(self.urlconf_name, six.string_types):
return import_module(self.urlconf_name)
else:
return self.urlconf_name
}}
というわけで、url_patternsの実体はメソッドでプロパティと...
**urls.pyの読み込み [#ga9e4ac1]
mysite/urls.pyはチュートリアルでは以下のように定義しまし...
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),
]
}}
url、また、includeを追っかける必要があります。それぞれ、d...
includeは長いので今回関係のあるところだけ抜き出すと、
#code(Python){{
def include(arg, namespace=None, app_name=None):
if isinstance(arg, tuple):
# 省略
else:
# No namespace hint - use manually provided names...
urlconf_module = arg
if isinstance(urlconf_module, six.string_types):
urlconf_module = import_module(urlconf_module)
patterns = getattr(urlconf_module, 'urlpatterns', url...
return (urlconf_module, app_name, namespace)
}}
ということで指定されたモジュール(polls.urls)を読み込ん...
#code(Python){{
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
}}
で、url関数。
#code(Python){{
def url(regex, view, kwargs=None, name=None):
if isinstance(view, (list, tuple)):
# For include(...) processing.
urlconf_module, app_name, namespace = view
return RegexURLResolver(regex, urlconf_module, kw...
elif callable(view):
return RegexURLPattern(regex, view, kwargs, name)
else:
raise TypeError('view must be a callable or a lis...
}}
view(第2引数)がタプルなのかcallableなのかによって返すオ...
さて、というわけで以上をまとめると、resolverというのは実...
RegexURLResolver(r'^/')
RegexURLResolver(r'^polls/') # mysite/urls.py
RegexURLPattern(r'^$', views.index) # polls/urls.py
これがわかるとresolveメソッドの動きが理解できるようになり...
**リクエストに対する処理関数の決定(具体例) [#k50badb4]
というわけで、get_resolver関数が返したRegexURLResolverのr...
#code(Python){{
for pattern in self.url_patterns:
try:
sub_match = pattern.resolve(new_path)
}}
と書いてあると、RegexURLResolverオブジェクト(r'polls/')...
#code(Python){{
class RegexURLPattern(LocaleRegexProvider):
def resolve(self, path):
match = self.regex.search(path)
if match:
# If there are any named groups, use those as...
# non-named groups. Otherwise, pass all non-n...
# positional arguments.
kwargs = match.groupdict()
args = () if kwargs else match.groups()
# In both cases, pass any extra_kwargs as **k...
kwargs.update(self.default_args)
return ResolverMatch(self.callback, args, kwa...
}}
で、それをRegexURLResolverのresolveメソッドが受け取り、自...
#code(Python){{
# Merge captured arguments in match with submatch
sub_match_dict = dict(match.groupdict(), **self.default_k...
sub_match_dict.update(sub_match.kwargs)
# If there are *any* named groups, ignore all non-named g...
# Otherwise, pass all non-named arguments as positional a...
sub_match_args = sub_match.args
if not sub_match_dict:
sub_match_args = match.groups() + sub_match.args
return ResolverMatch(
sub_match.func,
sub_match_args,
sub_match_dict,
sub_match.url_name,
[self.app_name] + sub_match.app_names,
[self.namespace] + sub_match.namespaces,
)
}}
これでようやく、リクエストパスに対する処理関数が取得でき...
**_get_responseその2 [#k8abb6a9]
というわけで_get_responseの続き。
#code(Python){{
# Apply view middleware
for middleware_method in self._view_middleware:
response = middleware_method(request, callback, c...
if response:
break
if response is None:
wrapped_callback = self.make_view_atomic(callback)
try:
response = wrapped_callback(request, *callbac...
except Exception as e:
response = self.process_exception_by_middlewa...
# Complain if the view returned None (a common error).
if response is None:
# 省略
# If the response supports deferred rendering, apply ...
# response middleware and then render the response
elif hasattr(response, 'render') and callable(respons...
for middleware_method in self._template_response_...
response = middleware_method(request, response)
# Complain if the template response middlewar...
if response is None:
# 省略
try:
response = response.render()
except Exception as e:
response = self.process_exception_by_middlewa...
return response
}}
make_view_atomicメソッドで何やらDB関連の処理をしています...
#code(Python){{
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the poll...
}}
HttpResponseにはrenderは定義されてません。きっとテンプレ...
*おわりに [#k540d554]
今回は標準モジュールのコード、Djangoのコード、自分の書い...
また、プロパティが使われていたり、オブジェクト構造が動的...
あ、convert_exception_to_response忘れた。もうかなり長くな...
-元々の関数を呼び出して例外(404とかもDjango的には例外と...
-resolverを呼び出してステータスコードに対応するエラーハン...
ページ名: