django之CBV用法詳解


基於類的視圖(CBV)

視圖是可調用的,它接收請求並返回響應。這可能不僅僅是一個函數,Django提供了一些可用作視圖的類的示例。這些允許您通過利用繼承和mixin來構建視圖並重用代碼。

基於類的視圖(Class-based views)提供了另一種將視圖實現為Python對象而不是函數的方法。它們不替換基於函數的視圖,但與基於函數的視圖相比具有一定的差異和優勢:

  • 提高了代碼的復用性,可以使用面向對象的技術,比如Mixin(多繼承)
  • 可以用不同的函數針對不同的HTTP方法處理,而不是通過很多if判斷,提高代碼可讀性

內建的基於類的視圖的層次結構:

  • 基本視圖:view 、TemplateView、RedirectView
  • 通用顯示視圖:DetailView、ListView
  • 通用編輯視圖:FormView、CreateView、 UpdateView、DeleteView
  • 通用日期視圖: ArchiveIndexView、YearArchiveView、 MonthArchiveView、 WeekArchiveView DayArchiveView、TodayArchiveView、DateDetailView
  • 基於類的視圖mixins
    • 簡單的mixins:ContextMixin、TemplateResponseMixin
    • 單個對象mixins:SingleObjectMixin、SingleObjectTemplateResponseMixin
    • 多個對象混合:MultipleObjectMixin、MultipleObjectTemplateResponseMixin

一、類視圖的基本使用

所有類視圖都繼承自Django提供的父類View,可以使用from django.views import View或from
django.views.generic import View來導入父類View。

#views.py
from django.urls import reverse
from django.views import View
from django.http import HttpResponse
from django.shortcuts import render, redirect
class Register(View):
     # 處理GET請求
     def get(self,request, *args, **kwargs):
     	return render(request,'App/register.html')
    
    # 處理POST請求
 def post(self, request, *args, **kwargs):
         # 注冊業務處理
         ...
         return redirect(reverse("App:login"))

路由注冊:

urlpatterns = [
     # 函數注冊
     path("register/",views.register,name='register')
     # 類視圖注冊
     path(r'register/',views.RegisterView.as_view(),name='register')
]

二、基本視圖

1.根視圖View類

提供適合各種應用程序的基本視圖類。所有視圖都繼承自 View 該類,該類處理將視圖鏈接到URL,HTTP方法調度和其他簡單功能。

View類核心代碼在as_view和dispatch方法中,其中as_view是類方法(@classonlymethod),只能通過類調用,不能通過對象調用,它是類視圖的入口點。注意這里調用的時候是通過類名.as_view()調用的。

其中,as_view方法主要執行邏輯:

@classonlymethod
 def as_view(cls, **initkwargs):
     """Main entry point for a request-response process."""
     # 參數檢查
     for key in initkwargs:
     	if key in cls.http_method_names: # 參數名不能是指定http的方法名
            raise TypeError("You tried to pass in the %s method name as a "
             "keyword argument to %s(). Don't do that."
             % (key, cls.__name__))
            
      	if not hasattr(cls, key): # 參數名必須是類已有屬性
 			raise TypeError("%s() received an invalid keyword %r. as_view "
 				"only accepts arguments that are already "
 				"attributes of the class." % (cls.__name__, key))
	
    # 視圖處理函數
     def view(request, *args, **kwargs):
        self = cls(**initkwargs) # 實例化當前類的對象
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
        self.setup(request, *args, **kwargs)
        if not hasattr(self, 'request'):
             raise AttributeError(
             "%s instance has no 'request' attribute. Did you override "
             "setup() and forget to call super()?" % cls.__name__
             )
        # 方法派發
        return self.dispatch(request, *args, **kwargs)
     view.view_class = cls
     view.view_initkwargs = initkwargs
    
     # take name and docstring from class
     update_wrapper(view, cls, updated=())
     # and possible attributes set by decorators
     # like csrf_exempt from dispatch
     update_wrapper(view, cls.dispatch, assigned=())
     return view # 返回視圖函數

整個as_view方法是一個裝飾器方法,它返回內部函數view,所以as_view()執行其實就是內部函數view執行。內部函數view主要邏輯就是:as_view()=>view()=>dispatch()=>相應的http方法

  • 實例化本類對象
  • 接收請求對象和參數(setup)
  • 調用dispatch方法進行派發

調用as_view方法可以傳遞參數,但要注意:

  • 不能使用請求方法的名字作為參數的名字
  • 只能接受視圖類已經存在的屬性對應的參數

dispatch方法是實例方法,它的主要代碼:

def dispatch(self, request, *args, **kwargs):
     #檢查請求方法是不是在http_method_names中包含
     #http_method_names包括八種方法:['get', 'post', 'put', 'patch', 'delete', 'head', 
     #'options', 'trace']
     if request.method.lower() in self.http_method_names:
    	 handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
     else: #不在調用http_method_not_allowed報錯
     	handler = self.http_method_not_allowed
     #調用和請求方法同名的實例方法處理用戶請求,實例方法需要用戶自己定義
     return handler(request, *args, **kwargs)

dispatch主要完成http請求方法的派發,調用視圖類對應實例方法處理用戶請求,所有用戶需要定義和http請求方法同名的實例方法完成功能,所以一般CBV的模塊寫法是:

from django.views import View

class IndexView(View):
 def get(self,request):
 	return HttpResponse("get")
 def post(self,request):
 	return HttpResponse("post")
 def put(self,request):
 	return HttpResponse("put")
 def delete(self,request):
 	return HttpResponse("delete")

2.TemplateView

TemplateView可以根據上下文渲染指定模板,返回響應對象。它繼承了ContentMixin、View、
TemplateResponseMixin。

  • ContentMixin用於獲取渲染模板的變量。你可以重寫get_context_data方法返回模板渲染的參數
  • TemplateResponseMixin 用於渲染模板
    • template_name模板文名(必須設置)
    • template_engine模板引擎(有默認值)
    • response_class模板渲染類,默認是TemplateResponse
    • content_type內容類型,默認是text/html
    • get_template_names你可以重寫這個方法返回模板名稱
#路由
urlpatterns = [
 url(r'^hello/(\w+)/$',views.HelloView.as_view(template_name='hello.html'),name='hello'),
]


#views.py
class HelloView(TemplateView):
 
 def get(self, request, *args, **kwargs):
 	context = self.get_context_data(**kwargs)
 	context['name'] = args[0]
 	return self.render_to_response(context)
  • 注意as_view方法參數只能是template_name、template_engine、response_class、content_type

3.RedirectView

重定向的指定url

get_redirect_url用於構造重定向的目標URL,可以重寫。

默認實現url用作起始字符串,並%使用URL中捕獲的命名組在該字符串中執行命名參數的擴展。

如果url未設置,則get_redirect_url()嘗試反轉 pattern_name使用URL中捕獲的內容(使用已命名和未命名的組)。

如果請求query_string,它還會將查詢字符串附加到生成的URL。子類可以實現他們希望的任何行為,只要該方法返回可重定向的URL字符串即可。

三、通用顯示視圖

本類視圖主要用戶數據展示,包括ListView顯示對象列表信息和DetailView顯示對象詳細信息

3.1 ListView

顯示對象列表頁面

  • MultipleObjectTemplateResponseMixin

    • 提供了模板文件名
    • 如果沒有指定模板文件名,則默認模板文件名規則是:應用名/模型名_list.html
  • MultipleObjectMixin

    核心類,提供了渲染模板所有需要的模型或查詢結果集(不一定是QuerySet,可以是對象列表),分頁。

    • queryset屬性用於渲染模板所需對象列表,也可以重寫get_queryset方法獲取

    • model,如果沒指定queryset,則根據指定model獲取對象列表

    • context_object_name模板中對象列表的名稱,如果不指定,則根據model獲取對象列表名稱:model_list

    • paginate_by指定分頁每頁的記錄個數,默認是None,不分頁

    • page_kwarg指定分頁請求路徑中命名分組名或get傳參中鍵的名稱,默認是page

    • paginate_orphans是指分頁最后一頁如果記錄不滿一頁的處理方式,默認是0,和前一頁合並顯示,如果不為0,則單獨顯示一頁

    • 分頁具體實現:

      def get_context_data(self, **kwargs):
           """
           Get the context for this view.
           """
           queryset = kwargs.pop('object_list',self.object_list)
          page_size = self.get_paginate_by(queryset)
       	context_object_name = self.get_context_object_name(queryset)
       	if page_size:
       		paginator, page, queryset, is_paginated = self.paginate_queryset(queryset, 
      page_size)
       		context = {
               'paginator': paginator, #在模板中可以使用分頁器
               'page_obj': page, #分頁對象
               'is_paginated': is_paginated,
               'object_list': queryset #當前頁數據
               }
       	else:
               context = {
               'paginator': None,
               'page_obj': None,
               'is_paginated': False,
               'object_list': queryset
               }
          if context_object_name is not None: #如果context_object_name不為空
       		context[context_object_name] = queryset
       	context.update(kwargs)
       	return super(MultipleObjectMixin, self).get_context_data(**context)
      
  • BaseListView默認實現get請求

3.2 DetailView

顯示對象的詳細信息

  • SingleObjectMixin
    • pk_url_kwarg 默認值pk,從請求路徑中獲取主鍵的值,請求路徑中參數必須是命名組,組名必須和pk_url_kwarg的值一樣
    • slug_url_kwarg默認值是slug,從請求路徑中獲取查詢參數sug的值,請求路徑中參數必須是命名組,組名必須和slug_url_kwarg的值一樣,如果參數中有pk_url_kwarg的值,則slug_url_kwarg不起作用
    • slug_field查詢字段的名稱
    • context_object_name模板中引用對象的名稱,默認模板中對象名稱是object

四、通用編輯視圖

本類視圖主要完成對象的增刪改。包括FormView、CreateView、 UpdateView、DeleteView

4.1 FormView

顯示表單的視圖。出錯時,重新顯示帶有驗證錯誤的表單;成功時,重定向到新的URL。

  • FormMixin
    • form_class 表單類名
    • success_url表單驗證成功后調整的url
    • form_valid() 驗證數據成功后的處理
    • form_invalid() 驗證不成功的處理
  • ProcessFormView
    • get渲染表單
    • post表單提交
    • put創建或修改對象

4.2 CreateView

顯示用於創建對象的表單的視圖,使用驗證錯誤(如果有)重新顯示表單並保存對象

  • 重要屬性:
    • template_name模板文件名
    • fields指定的字段列表
    • model關聯模型名
    • form_class表單類,如果沒有設置會默認是模型名

4.3 UpdateView

UpdateView的用法和CreateView基本一樣

4.4 DeleteView

刪除指定對象的視圖

五、類視圖使用裝飾器

為類視圖添加裝飾器,可以使用兩種方法。

為了理解方便,我們先來定義一個為函數視圖准備的裝飾器(在設計裝飾器時基本都以函數視圖作為考慮的被裝飾對象),及一個要被裝飾的類視圖。

def my_decorator(func):
 	def wrapper(request, *args, **kwargs):
         print('自定義裝飾器被調用了')
         print('請求路徑%s' % request.path)
         return func(request, *args, **kwargs)
 	return wrapper

class DemoView(View):
	 def get(self, request):
 		print('get方法')
 		return HttpResponse('ok')
    
 	def post(self, request):
 		print('post方法')
 		return HttpResponse('ok')

在類視圖中使用為函數視圖准備的裝飾器時,不能直接添加裝飾器,需要使用method_decorator將其轉換為適用於類視圖方法的裝飾器。

method_decorator裝飾器使用name參數指明被裝飾的方法

# 為全部請求方法添加裝飾器
@method_decorator(my_decorator, name='dispatch')
class DemoView(View):
     def get(self, request):
     	print('get方法')
     	return HttpResponse('ok')
    
     def post(self, request):
     	print('post方法')
     	return HttpResponse('ok')
    
 # 為特定請求方法添加裝飾器
@method_decorator(my_decorator, name='get')
class DemoView(View):
 	def get(self, request):
 		print('get方法')
 		return HttpResponse('ok')
    
 	def post(self, request):
 		print('post方法')
 		return HttpResponse('ok')

如果需要為類視圖的多個方法添加裝飾器,但又不是所有的方法(為所有方法添加裝飾器參考上面例子),可以直接在需要添加裝飾器的方法上使用method_decorator,如下所示

from django.utils.decorators import method_decorator
# 為特定請求方法添加裝飾器
class DemoView(View):
     @method_decorator(my_decorator) # 為get方法添加了裝飾器
     def get(self, request):
 		print('get方法')
 		return HttpResponse('ok')
    
 	@method_decorator(my_decorator) # 為post方法添加了裝飾器
	 def post(self, request):
 		print('post方法')
		 return HttpResponse('ok')
        
     def put(self, request): # 沒有為put方法添加裝飾器
     	print('put方法')
     	return HttpResponse('ok')


免責聲明!

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



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