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里面正則的捕獲參數


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM