Я погружаюсь в общие представления Django, выясняя, как они возвращают простой объект HttpResponse, как простая функция просмотра.
Я написал простой проект для тестирования, и я добавил некоторые команды ведения журнала к базовому классу View, определенному в файле django/views/generic/base.py, чтобы я мог отслеживать, что происходит под капотом.
У меня есть некоторые вопросы, которые возникли во время моих исследований.
Однако я старался сохранить этот пост коротким, но для полного понимания я счел необходимым включить фрагменты кода и журналы.
Я буду очень благодарен всем, кто найдет время, чтобы дать некоторые полезные комментарии, возможно, отвечая на некоторые из моих вопросов.
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))
Джанго/вид/общий/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.
Разве что он создает новый экземпляр View с initkwargs и присваивает его экземпляру в использовании (self)?
Если да, то зачем это нужно?
4.
Как мы можем использовать initkwargs (аргументы as_view)?