在上一篇Django处理http请求流程剖析中,笔者详细地说明了Django框架是如何根据WSGI协议处理一个Http请求的。其中,处理开发者自行定义的View的代码如下:
# django.core.handlers.base.py
# 路由解析
resolver_match = resolver.resolve(request.path_info)
callback, callback_args, callback_kwargs = resolver_match
request.resolver_match = resolver_match
# 执行view函数
if response is None:
wrapped_callback = self.make_view_atomic(callback)
try:
response = wrapped_callback(request, *callback_args, **callback_kwargs)
except Exception as e:
response = self.process_exception_by_middleware(e, request)
如果开发者使用的是函数视图(FBV),这段代码非常好理解,wrapped_back就是该函数视图,直接调用即可。
但是如果是类视图呢,Django是如何将类视图转化为一个函数呢?
CBV.as_view()
在Django的路由中为url指定view的时候,如果为类视图(所有类视图都需要继承于基类View),则需要使用as_view方法将类视图转化为一个函数,接下来笔者就分析一下as_view方法的源码。
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', 'patch', 'delete', 'head', 'options', 'trace']
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 six.iteritems(kwargs):
setattr(self, key, value)
# 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("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attribu