[轉載注明出處: 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里面正則的捕獲參數