zoukankan      html  css  js  c++  java
  • 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里面正则的捕获参数

  • 相关阅读:
    TensorFlow基础篇
    MySql分类
    VISUAL STUDIO 调试
    排序分类
    位分类
    Visio分类
    工作线程AfxBeginThread的使用
    Windows Live Writer配置步骤
    用户界面线程AfxBeginThread的使用
    WIndows 相关知识
  • 原文地址:https://www.cnblogs.com/yukityan/p/8039041.html
Copyright © 2011-2022 走看看