[转载注明出处: http://www.cnblogs.com/yukityan/p/8039041.html ]
django内置列表视图:
# 导入 from django.views.generic import ListView # ListView继承的模块 class ListView(MultipleObjectTemplateResponseMixin, BaseListView): pass # BaseListView继承的模块 class BaseListView(MultipleObjectMixin, View): """ 定义了get()方法,提供给View中的dispatch方法予以调度 """ def get(): pass # MultipleObjectMixin继承的模块 class MultipleObjectMixin(ContextMixin): """ 定义了与queryset相关的一些方法,以及一些自身属性,提供多种途径获取queryset以及完成分页功能 """ pass
响应入口:
1.首先在url配置中,我们调用django基础View视图的as_view()
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)
1 @classonlymethod # 装饰器,根据源码注释,点明这是一个属于类的方法,实例基于类生成的实例没有不能调用 2 def as_view(cls, **initkwargs): 3 """ 4 Main entry point for a request-response process. 5 """ 6 for key in initkwargs: 7 if key in cls.http_method_names: 8 raise TypeError("You tried to pass in the %s method name as a " 9 "keyword argument to %s(). Don't do that." 10 % (key, cls.__name__)) 11 if not hasattr(cls, key): 12 raise TypeError("%s() received an invalid keyword %r. as_view " 13 "only accepts arguments that are already " 14 "attributes of the class." % (cls.__name__, key)) 15 16 def view(request, *args, **kwargs): 17 self = cls(**initkwargs) 18 if hasattr(self, 'get') and not hasattr(self, 'head'): 19 self.head = self.get 20 self.request = request 21 self.args = args 22 self.kwargs = kwargs 23 return self.dispatch(request, *args, **kwargs) 24 view.view_class = cls 25 view.view_initkwargs = initkwargs 26 27 # take name and docstring from class 28 update_wrapper(view, cls, updated=()) 29 30 # and possible attributes set by decorators 31 # like csrf_exempt from dispatch 32 update_wrapper(view, cls.dispatch, assigned=()) 33 return view
在url配置里面,我们配置的LIstView.as_view(),在项目启动时django就会自动运行as_view()方法,注意我们这里配置的是as_view(),而不是像函数视图一样的xxxview,这里的as_view完成的是类似于装饰器的用法,as_view()>return view:返回的是一个函数对象,然后再as_view()用到了装饰器:classonlymethod,说明这是一个属于类的方法,类生产的实例是没有办法调用的.as_view()对于接收的参数进行检查,所以在as_view(x='x', xx ='xx', xxx='xxx')是接收的参数名不能够与http_method_names中的http响应方法冲突且只能够是类拥有的属性.这里的意义在于,像我们使用ListView时,我们可以在views.py中编写一个类继承ListView,然后在书写类代码的时候,在其中定义我们的类属性,但是当我们两个视图功能相近时,我们完全可以调用在url中调用同一个类的as_view()方法,然后在参数中设置其属性值,比如最简单的显示两个不同model的queryset,我们在as_view()的参数传递中url(xxx, as_view(model=model1), xxx),url(xxxx,as_view(model=model2), xxxx ).
然后函数view完成的是:当request传递进来时实例化这个类(17行)self = cls(**initkwargs),然后调用实例的dispatch方法,再调用相应的http_method处理request请求.这也就是为什么当我们继承了django中的django.view.generic.base.View时需要我们自己写get方法或者post方法了.在而BaseListView中,django已经写好了对应的get方法.
class BaseListView(MultipleObjectMixin, View): """ A base view for displaying a list of objects. """ def get(self, request, *args, **kwargs): self.object_list = self.get_queryset() allow_empty = self.get_allow_empty() if not allow_empty: # When pagination is enabled and object_list is a queryset, # it's better to do a cheap query than to load the unpaginated # queryset in memory. if self.get_paginate_by(self.object_list) is not None and hasattr(self.object_list, 'exists'): is_empty = not self.object_list.exists() else: is_empty = len(self.object_list) == 0 if is_empty: raise Http404(_("Empty list and '%(class_name)s.allow_empty' is False.") % { 'class_name': self.__class__.__name__, }) context = self.get_context_data() return self.render_to_response(context)
然后在BaseListView.get方法中,就是类似与我们自己编写的函数视图流程,而且因为继承了MultipleObjectMixin这个类,这个类里面定义了像
class MultipleObjectMixin(ContextMixin): """ A mixin for views manipulating multiple objects. """ allow_empty = True queryset = None model = None paginate_by = None paginate_orphans = 0 context_object_name = None paginator_class = Paginator page_kwarg = 'page' ordering = None pass
等等一些属性和方法,使得在as_view()中我们就可以直接传递不同参数来配置不同的视图,而不用重新编写一个类了.所以这里最重要的是了解类的继承机制,同时了解django分发流程,通过一类编写一类视图让开发过程更加方便.
项目启动(as_view())>request请求(as_view函数中返回的view函数对象)>实例的dispatch方法>实例相对应的http_method
参数传递
as_view(xxx='xxx')(设置类属性),
view(request, *args, **kwargs)接收request,和url里面正则的捕获参数
dispatch接收request,和url里面正则的捕获参数,
http_method接收request,和url里面正则的捕获参数