最短時間攻透最完善的Python框架——Django⑪

類視圖

簡潔明瞭:在Django中可以使用類來定義一個視圖,稱爲類視圖

1.類視圖引入

以函數的方式定義的視圖稱爲函數視圖,函數視圖便於理解。但是遇到一個視圖對應的路徑提供了多種不同HTTP請求方式的支持時,便需要在一個函數中編寫不同的業務邏輯,代碼可讀性與複用性都不佳。

 def register(request):
    """處理註冊"""

    # 獲取請求方法,判斷是GET/POST請求
    if request.method == 'GET':
        # 處理GET請求,返回註冊頁面
        return render(request, 'register.html')
    else:
        # 處理POST請求,實現註冊邏輯
        return HttpResponse('這裏實現註冊邏輯')

使用類視圖可以將視圖對應的不同請求方式以類中的不同方法來區別定義。如下所示

from django.views.generic import View

class RegisterView(View):
    """類視圖:處理註冊"""

    def get(self, request):
        """處理GET請求,返回註冊頁面"""
        return render(request, 'register.html')

    def post(self, request):
        """處理POST請求,實現註冊邏輯"""
        return HttpResponse('這裏實現註冊邏輯')

定義類視圖需要繼承自Django提供的父類View,可使用如下代碼導入

from django.views.generic import View

#或者

from django.views.generic.base import View`

類視圖的好處:

  • 代碼可讀性好
  • 類視圖相對於函數視圖有更高的複用性, 如果其他地方需要用到某個類視圖的某個特定邏輯,直接繼承該類視圖即可

2.類視圖使用

配置路由時,使用類視圖的as_view()方法來添加

urlpatterns = [
    # 視圖函數:註冊
    # url(r'^register/$', views.register, name='register'),
    # path('register/', views.register, name='register'), #Django2.x系列開始使用,需要導入path包
    # 類視圖:註冊    
    url(r'^register/$', views.RegisterView.as_view(), name='register'),
]

3.類視圖原理

    @classonlymethod
    def as_view(cls, **initkwargs):
        #...省略......代碼...

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)  #解包
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            # 此處我們調用dispatch方法,按照不同請求方式調用不同請求方法
            return self.dispatch(request, *args, **kwargs)

        #...省略......代碼...

        # 返回真正的函數視圖
        return view


    def dispatch(self, request, *args, **kwargs):
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

4.類視圖使用裝飾器

爲類視圖添加裝飾器,可以使用兩種方法**(在URL配置中裝飾,在類視圖中裝飾)**

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

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')

4.1 在URL配置中裝飾

urlpatterns = [
    url(r'^demo/$', my_decorate(DemoView.as_view()))
]

此種方式最簡單,但因裝飾行爲被放置到了url配置中,單看視圖的時候無法知道此視圖還被添加了裝飾器,不利於代碼的完整性,不建議使用。

此種方式會爲類視圖中的所有請求方法都加上裝飾器行爲(因爲是在視圖入口處,分發請求方式前)。

4.2 在類視圖中裝飾

在類視圖中使用爲函數視圖準備的裝飾器時,不能直接添加裝飾器,需要使用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')

5.類視圖Mixin擴展類

使用面向對象多繼承的特性,可以通過定義父類(作爲擴展類),在父類中定義想要向類視圖補充的方法,類視圖繼承這些擴展父類,便可實現代碼複用。

定義的擴展父類名稱通常以Mixin結尾。

舉例如下:

class ListModelMixin(object):
    def list(self, request, *args, **kwargs):
        pass

class CreateModelMixin(object):
    def create(self, request, *args, **kwargs):
        pass

class BooksView(CreateModelMixin, ListModelMixin, View):
    """
    同時繼承兩個擴展類,複用list和create方法
    """
    def get(self, request):
        self.list(request)
        ...

    def post(self, request):
        self.create(request)
        ...

class SaveOrderView(CreateModelMixin, View):
    """
    繼承CreateModelMixin擴展類,複用create方法
    """
    def post(self, request):
        self.create(request)
        ...

內容有點多,但是View這一塊還是比較重要的,所以希望大家認真閱讀
昨天去過節了,沒有及時更新,在此致歉,今天會按時補上,希望每一篇博文都能夠幫到需要的你

@Author:HaoXuan

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章