Base.py
class View 下面先创建了一个类属性http_method_names
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
一个包含了所有HTTP协议会用到的方法名称的字符串
def __init__(self, **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.items():
setattr(self, key, value)
在类的构造器里面定义一个初始化魔术方法:
for key, value in kwargs.items():
setattr(self, key, value)
我们之前学习过setattr
的魔术是setattr(x, 'y', v) is equivalent to ``x.y = v
紧接着在类方法里 定义as_view()
as_view()
@classonlymethod
def as_view(cls, **initkwargs):
"""Main entry point for a request-response process."""
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError(
'The method name %s is not accepted as a keyword argument '
'to %s().' % (key, cls.__name__)
)
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key))
def view(request, *args, **kwargs):
self = cls(**initkwargs)
self.setup(request, *args, **kwargs)
if not hasattr(self, 'request'):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
# 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=())
return view
经过@classonlymethod
装饰器的装饰后,as_veiw()解读:
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError(
'The method name %s is not accepted as a keyword argument '
'to %s().' % (key, cls.__name__)
)
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key))
initkwar
是类构造器里面传入的参数,通过key遍历在for列表里面循环:http_method_names
里面的名字。
如果存在就捕获不接受方法名称作为关键字参数
。如果不在就捕获收到一个无效的关键字 %r。只接受已经是类属性的参数。
接下来走到我们要看的view()
方法
def view(request, *args, **kwargs):
self = cls(**initkwargs)
self.setup(request, *args, **kwargs)
if not hasattr(self, 'request'):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
return self.dispatch(request, *args, **kwargs)
如果对象没有request
方法,捕获异常。如果有,通过return调用dispatch
方法。
什么是 dispatch
方法呢?
dispatch()
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.
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
return handler(request, *args, **kwargs)
翻译方法注释:
尝试分派到正确的方法;如果方法不存在,则转到错误处理程序。如果请求方法不在批准列表中,也会延迟到错误处理程序。
通过转换从view
传过来的request
的method
转换成字符串小写,然后判断是否在类属性下的self.http_method_names
列表里面。
分别设置handler
(处理器)
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
和
handler = self.http_method_not_allowed
然后返回这个处理器给 view()
return handler(request, *args, **kwargs)
然后经过update_wrapper
把他变成一个wrapped function
(我们这里先暂时不讲什么是wrapped function
不过附带上 update_wrapper
的源码, 可以自己看一下
update_wrapper()
def update_wrapper(wrapper,
wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
"""Update a wrapper function to look like the wrapped function
wrapper is the function to be updated
wrapped is the original function
assigned is a tuple naming the attributes assigned directly
from the wrapped function to the wrapper function (defaults to
functools.WRAPPER_ASSIGNMENTS)
updated is a tuple naming the attributes of the wrapper that
are updated with the corresponding attribute from the wrapped
function (defaults to functools.WRAPPER_UPDATES)
"""
for attr in assigned:
try:
value = getattr(wrapped, attr)
except AttributeError:
pass
else:
setattr(wrapper, attr, value)
for attr in updated:
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
# Issue #17482: set __wrapped__ last so we don't inadvertently copy it
# from the wrapped function when updating __dict__
wrapper.__wrapped__ = wrapped
# Return the wrapper so this can be used as a decorator via partial()
return wrapper
携带的四个参数
wrapper,
wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES
分别代表的意思:
wrapper is the function to be updated # 要被更新的函数
wrapped is the original function # 原有的函数
assigned is a tuple naming the attributes assigned directly
from the wrapped function to the wrapper function (defaults to
functools.WRAPPER_ASSIGNMENTS) # 直接分发的属性(有默认值)
updated is a tuple naming the attributes of the wrapper that
are updated with the corresponding attribute from the wrapped
function (defaults to functools.WRAPPER_UPDATES)# 是一个元组,其中命名了包装器的属性,这些属性会用被包装函数的相应属性更新
return
最后的最后,返回 view
, 这个是已经被包装好的 view
函数名。这也是为什么我们一般在路由层里面写的as_view()()
要加两个括号,就是为了调用 base.py返回出来的这个 view
+()= 调用