django: ListView解读

[转载注明出处: 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里面正则的捕获参数

posted @ 2017-12-15 03:35  雪雪PAI  阅读(5399)  评论(0编辑  收藏  举报