私はDjangoの一般的なビューに飛び込み、単純なビュー関数のように、単純なHttpResponseオブジェクトを返す方法を理解しています。
テスト用の簡単なプロジェクトを作成し、ファイルdjango / views / generic / base.pyで定義されている基本的なViewクラスにいくつかのログコマンドを追加して、内部で何が起こっているかを追跡できるようにしました。
研究中に出てきた質問がいくつかあります。
私はこの投稿を短くしようと努めてきましたが、完全に理解するには、コードスニペットとログを含めることが不可欠だと感じました。
時間を割いて有益なコメントをしてくれて、おそらく私の質問のいくつかに答えてくれた人には本当に感謝しています。
urls.py
from django.conf.urls import patterns, url
from views import WelcomeView
urlpatterns = patterns('',
url(r'^welcome/(?P<name>\w+)/$', WelcomeView.as_view()),
)
views.py
from django.http import HttpResponse
from django.views.generic import View
class WelcomeView(View):
def get(self, request, name):
return HttpResponse('What is up, {0}?'.format(name))
django / views / generic / base.py
class View(object):
"""
Intentionally simple parent class for all views. Only implements
dispatch-by-method and simple sanity checking.
"""
http_method_names = ['get', 'post', 'put', 'delete', 'head', 'options', 'trace']
def __init__(self, **kwargs):
#####logging
logging.error('*** View.__init__ is started with kwargs: {0} ***'.format(
repr(kwargs)))
"""
Constructor. Called in the URLconf; can contain helpful extra
keyword arguments, and other things.
"""
# Go through keyword arguments, and either save their values to our
# instance, or raise an error.
for key, value in kwargs.iteritems():
setattr(self, key, value)
#####logging
logging.error('*** View.__init__ reached its end. No return value. ***')
@classonlymethod
def as_view(cls, **initkwargs):
#####logging
logging.error('*** View.as_view is started with initkwargs: {0} ***'.format(
repr(initkwargs)))
"""
Main entry point for a request-response process.
"""
# sanitize keyword arguments
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError(u"You tried to pass in the %s method name as a "
u"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError(u"%s() received an invalid keyword %r" % (
cls.__name__, key))
def view(request, *args, **kwargs):
#####logging
logging.error('*** View.as_view.view is called with args: {0};\
and kwargs: {1} ***'.format(
repr(args),
repr(kwargs)))
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
#####logging
logging.error('*** View.as_view.view reached its end.\
Now calls dispatch() and returns the return value.')
return self.dispatch(request, *args, **kwargs)
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
#####logging
logging.error('*** View.as_view reached its end. Now returns view. ***')
return view
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
#####logging
logging.error('*** View.dispatch called, with args: {0};\
and kwargs: {1} ***'.format(
repr(args),
repr(kwargs)))
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
self.request = request
self.args = args
self.kwargs = kwargs
#####logging
logging.error('*** View.dispatch reached its end.\
Now calls handler and returns the return value. ***')
return handler(request, *args, **kwargs)
def http_method_not_allowed(self, request, *args, **kwargs):
allowed_methods = [m for m in self.http_method_names if hasattr(self, m)]
logger.warning('Method Not Allowed (%s): %s', request.method, request.path,
extra={
'status_code': 405,
'request': self.request
}
)
return http.HttpResponseNotAllowed(allowed_methods)
いくつかのテストリクエストからのログ
Django version 1.4.5, using settings 'try1.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
ERROR:root:*** View.as_view is started with initkwargs: {} ***
ERROR:root:*** View.as_view reached its end. Now returns view. ***
ERROR:root:*** View.as_view.view is called with args: (); and kwargs: {'name': u'Dude'} ***
ERROR:root:*** View.__init__ is started with kwargs: {} ***
ERROR:root:*** View.__init__ reached its end. No return value. ***
ERROR:root:*** View.as_view.view reached its end. Now calls dispatch() and returns the return value.
ERROR:root:*** View.dispatch called, with args: (); and kwargs: {'name': u'Dude'} ***
ERROR:root:*** View.dispatch reached its end. Now calls handler and returns the return value. ***
[24/Feb/2013 12:43:19] "GET /welcome/Dude/ HTTP/1.1" 200 17
ERROR:root:*** View.as_view.view is called with args: (); and kwargs: {'name': u'Dude'} ***
ERROR:root:*** View.__init__ is started with kwargs: {} ***
ERROR:root:*** View.__init__ reached its end. No return value. ***
ERROR:root:*** View.as_view.view reached its end. Now calls dispatch() and returns the return value.
ERROR:root:*** View.dispatch called, with args: (); and kwargs: {'name': u'Dude'} ***
ERROR:root:*** View.dispatch reached its end. Now calls handler and returns the return value. ***
[24/Feb/2013 12:43:32] "GET /welcome/Dude/ HTTP/1.1" 200 17
[24/Feb/2013 12:44:43] "GET /welcome/ HTTP/1.1" 404 1939
ERROR:root:*** View.as_view.view is called with args: (); and kwargs: {'name': u'Bro'} ***
ERROR:root:*** View.__init__ is started with kwargs: {} ***
ERROR:root:*** View.__init__ reached its end. No return value. ***
ERROR:root:*** View.as_view.view reached its end. Now calls dispatch() and returns the return value.
ERROR:root:*** View.dispatch called, with args: (); and kwargs: {'name': u'Bro'} ***
ERROR:root:*** View.dispatch reached its end. Now calls handler and returns the return value. ***
[24/Feb/2013 12:44:59] "GET /welcome/Bro/ HTTP/1.1" 200 16
結局のところ、私の質問
1.
ログによると、as_viewはView.initの前に呼び出されます。
Viewインスタンスを作成する前でもViewメソッドを呼び出すということですか?
2.
as_view()が最初の呼び出しで実行された後に呼び出されないのはなぜですか?
私はまだPythonのインポート、コンパイル、メモリ使用の専門家ではありませんが、
ここでそれらが何らかの役割を果たしていると感じています。
3.
view()の定義で、次のスニペットは何をしますか?
self = cls(**initkwargs)
ログによると、View.initをトリガーします。
initkwargsを使用して新しいViewインスタンスを作成し、それを使用中のインスタンス(self)に割り当てますか?
もしそうなら、なぜそれが必要なのですか?
4.
initkwargs(as_viewの引数)をどのように利用できますか?