Django中的as_view方法源码分析
Posted ludundun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django中的as_view方法源码分析相关的知识,希望对你有一定的参考价值。
django的类视图拥有自动查找指定方法的功能,通过调用as_views()方法实现。
在探讨这个问题之前,先引入一段代码举个例子方便理解:
一般请求的判断方法:
def View(request,*args,**kwargs):
if request.method.lower() == 'get':
do_something()
if request.method.lower() == 'post':
do_something()
编写自定义的视图类,前提必须要继承基类View,然后使用View.as_view()代替判断:
class ClassName(View):
'''
继承View自动判断请求方法
'''
def post():
pass
def get():
pass
def other():
pass
#调用方法
url(url, ClassName.as_view(), name)
设计思想:把视图函数的逻辑定义到类的方法里面去,然后在函数中实例化这个类,通过调用类的方法实现函数逻辑。而把逻辑定义在类中的一个好处就是可以通过继承复用这些方法。
那么问题来了,as_view()这个方法是如何执行对应自定义的get或者post方法呢?
as_view
如果你曾经使用过类视图,那么最熟悉的应该就是这个方法了。要想让类视图生效,必须在 urls.py 的 URL 模式(Pattern)里做类似如下的配置:
# urls.py
from .views import IndexView # 导入自定义的视图类
urlpatterns = [
url(r^'^$',IndexView.as_view(),name='index')
]
Django 使用如上的方式配置 URL 到对应视图函数的路由映射。注意到 url() 函数前两个位置参数需要传递的值,第一个是需要捕获的 url 的正则模式,第二个参数则是一个可调用的对象(即视图函数)。如果我们通过 def 定义视图函数,那么传入的这个可调用对象就是这个函数本身;而如果我们定义的是类视图,则必须调用类视图的 as_view 方法返回一个根据这个类生成的可调用对象。类视图所有的魔法就在这个函数里了,来看看 Django 究竟是如何神奇地把一个类转为一个函数的。
@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 "
"attributes of the class." % (cls.__name__, key))
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
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
as_view 方法被调用时允许传递一些关键字参数,不过需要做一个点点检查,第一防止你传入诸如 get、post 这样的关键字参数把类本身的 get、post 方法覆盖了;第二是防止你传入未定义为类属性的参数。最开始的 for 循环就是做这个事。
接下来在 as_view 方法中又定义了一个 view 方法,这个方法相信如果你经常写视图函数的话应该非常眼熟,这就是视图函数的标准定义:接收一个 HttpRequest 对象,以及从 url 捕获的非命名组和命名组参数。只不过在 view 这个视图函数里还多做了一点事,它首先实例化了一个类视图对象,然后把函数的参数设置为了这个类视图实例的属性,接着便调用了实例的 dispatch 方法返回视图函数被要求返回的 HttpResponse 对象(注意 dispatch 方法会根据 HTTP 请求方法的不同去调用对应的处理方法)。接着把类中的一些文档字符串和函数名等更新到定义的 view 函数中,然后 as_view 方法返回这个 view 函数。
调用顺序: as_view --> view --> dispatch
可以看出as_view实际上是一个闭包,他的作用就是做一些检验工作,再返回view方法
而view方法的作用是给请求对象补充三个参数,并调用dispatch方法处理
dispatch方法查找到指定的请求方法,并执行相应代码块
可以得出结论:as_view方法实际上最后就是要调用dispatch方法
所以回过头来再看一下我们的 url 模式定义:
urlpatterns = [
url(r^'^$',IndexView.as_view(),name='index')
]
views.IndexView.as_view() 调用后返回的就是一个在 IndexView 里通过 def 定义的视图函数 view(注意所有类视图都继承自 View 基类),是不是和你直接在这里放一个视图函数是一样的?
附加一张图片加深印象:
总结
现在我们已经明白了类视图的基本结构,其主要功能就是根据 HTTP 请求方法的不同做出相应处理,具体的实现为 dispatch 方法。类视图的核心思想就是把视图函数的逻辑定义到类的方法里面去,然后在函数中实例化这个类,通过调用类的方法实现函数逻辑。
以上是关于Django中的as_view方法源码分析的主要内容,如果未能解决你的问题,请参考以下文章
Django 之restfromwork 源码---APIView 分析