Django 類視圖(二)類視圖介紹

本文是對 Django 官網(wǎng)文檔的翻譯。

官網(wǎng)鏈接:https://docs.djangoproject.com/en/1.11/topics/class-based-views/intro/

適用版本:Django1.11

類視圖提供了一種使用 Python 對象實現(xiàn)視圖的方法。類視圖不會替代函數(shù)視圖, 與函數(shù)視圖相比,它們有一定的差異和優(yōu)勢:

  • 采用單獨的函數(shù)來處理特定 HTTP 請求(GET,POST等)代替函數(shù)視圖的條件分支。

  • 可以使用面向?qū)ο蟮募夹g(shù),如 mixins(多重繼承)將代碼重新定義為可重用的組件。

通用視圖、類視圖和通用類視圖之間的關(guān)系和歷史


最初,只有視圖函數(shù),Django 將 HttpRequest 傳遞給函數(shù)并且期望返回一個 HttpResponse 。 這是 Django 的工作范圍。

早期的開發(fā)發(fā)現(xiàn)了視圖中共同的習(xí)語和模式,因此引入了函數(shù)通用視圖來抽象這些模式,從而簡化常見視圖開發(fā)。

函數(shù)通用視圖雖然可以很好地處理簡單情況,但是超出一些簡單配置選項后就沒有辦法對它們進行擴展或定制了,這限制了它們在許多現(xiàn)實應(yīng)用程序中的使用。

創(chuàng)建類通用視圖與創(chuàng)建函數(shù)通用視圖的目的相同(使視圖開發(fā)更容易)。然而,使用 mixins 來實現(xiàn)的解決方案比采用函數(shù)通用視圖更具擴展性和靈活性。

如果您以前曾嘗試過函數(shù)通用視圖,并發(fā)現(xiàn)了它們的缺點,那么不應(yīng)該將類通用視圖簡單地看做函數(shù)通用視圖的類方式等效,而應(yīng)該看做是解決通用視圖問題的新方法。

Django 構(gòu)建類通用視圖的基類和 mixins 工具包非常靈活,它為簡單應(yīng)用可能涉及到的默認(rèn)方法和屬性提供了很多鉤子。例如,不僅可以通過為 form_class 賦值設(shè)置類屬性,還可以使用 get_form 方法設(shè)置類屬性,默認(rèn)情況下,該方法調(diào)用只返回類的 form_class 屬性的 get_form_class 方法。這為設(shè)置表單提供了從簡單屬性到完全動態(tài)調(diào)用掛接等多種選項。這些選項看起來像增加了簡單情況的復(fù)雜性,但如果沒有這些選項,更高級的設(shè)計將受到限制。

使用類視圖


類視圖的核心思想在于使用不同的類實例方法響應(yīng)不同的 HTTP 請求方法,而不是在單個視圖函數(shù)中使用條件分支代碼。

視圖函數(shù)處理 HTTP GET 的代碼是這樣的:

from django.http import HttpResponse

def my_view(request):
    if request.method == 'GET':
        # <view logic>
        return HttpResponse('result')

在類視圖中,它將變?yōu)椋?/p>

from django.http import HttpResponse
from django.views import View

class MyView(View):
    def get(self, request):
        # <view logic>
        return HttpResponse('result')

由于 Django 的 URL 解析器希望將請求和關(guān)聯(lián)的參數(shù)發(fā)送到可調(diào)用函數(shù)(而不是類),類視圖定義了一個 as_view() 方法,該方法為匹配關(guān)聯(lián) URL 模式的請求提供一個可調(diào)用函數(shù)。as_views() 函數(shù)創(chuàng)建一個類實例并調(diào)用該類實例的 dispatch() 方法。 dispatch 對請求進行分析,確定請求類型(GET,POST等)并將請求匹配到對應(yīng)方法(如果已定義對應(yīng)方法),或引發(fā) HttpResponseNotAllowed 異常(如果沒定義對應(yīng)方法):

# urls.py
from django.conf.urls import url
from myapp.views import MyView

urlpatterns = [
    url(r'^about/$', MyView.as_view()),
]

值得注意的是,類方法返回的內(nèi)容與函數(shù)視圖返回的內(nèi)容相同,都是某種形式的 HttpResponse 。 這意味著 http快捷函數(shù) 或 TemplateResponse 對象在類視圖中是有效的。

雖然最小的類視圖不需要設(shè)置任何類屬性就可以實現(xiàn)工作,類屬性在許多類設(shè)計中非常有用,我們可以通過兩種方式配置或設(shè)置類屬性:

第一種方法是標(biāo)準(zhǔn)的 Python 方法--在子類中覆蓋屬性和方法。 如果父類有一個 greeting 屬性:

from django.http import HttpResponse
from django.views import View

class GreetingView(View):
    greeting = "Good Day"

    def get(self, request):
        return HttpResponse(self.greeting)

可以在子類中這樣重寫:

class MorningGreetingView(GreetingView):
    greeting = "Morning to ya"

另一種方法是在 URLconf 中的 as_views() 中以關(guān)鍵詞參數(shù)的形式進行配置。

urlpatterns = [
   url(r'^about/$', GreetingView.as_view(greeting="G'day")),
]

注意:為請求實例化視圖類時,通過 as_view() 入口設(shè)置的類屬性只在定義 URL 時配置一次。

使用mixins


Mixins是一種多繼承的形式,在多繼承中多個父類的行為和屬性可以互相結(jié)合。

例如,通用類視圖中有一個名為 TemplateResponseMixin 的 mixin ,它的主要作用是定義render_to_response()方法。當(dāng)與 View 類的行進行結(jié)合時,結(jié)果是 TemplateView 類。TemplateView 類將請求分配給合適的匹配方法( View 類定義的行為),并通過輸入 template_name 屬性的 render_to_reponse() 方法返回一個TemplateResponse 對象( TemplateResponseMixin 定義的一個行為)。

Mixins 是在多個類中重用代碼的絕佳方法,但是使用它們也需要一些代價。 代碼分散到 mixins 中越多,閱讀一個子類并知道它能做什么就越困難,當(dāng)創(chuàng)建具有深繼承樹的類的子類時,也越難知道要重寫哪個 mixin 的哪個方法。

還要注意,只能繼承一個通用視圖,也就是說,只有一個父類可以繼承 View ,而其余的(如果有的話)應(yīng)該繼承 mixins 。 嘗試?yán)^承多個繼承 View 的類將無法正常工作,例如,嘗試組合 ProcessFormView 和 ListView 實現(xiàn)在列表頂部使用表單不會得到預(yù)期的結(jié)果。

使用類視圖處理表單


處理表單的函數(shù)視圖看起來是這樣的:

from django.http import HttpResponseRedirect
from django.shortcuts import render

from .forms import MyForm

def myview(request):
    if request.method == "POST":
        form = MyForm(request.POST)
        if form.is_valid():
            # <process form cleaned data>
            return HttpResponseRedirect('/success/')
    else:
        form = MyForm(initial={'key': 'value'})

    return render(request, 'form_template.html', {'form': form})

對應(yīng)的類視圖是這樣的:

from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views import View

from .forms import MyForm

class MyFormView(View):
    form_class = MyForm
    initial = {'key': 'value'}
    template_name = 'form_template.html'

    def get(self, request, *args, **kwargs):
        form = self.form_class(initial=self.initial)
        return render(request, self.template_name, {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            # <process form cleaned data>
            return HttpResponseRedirect('/success/')

        return render(request, self.template_name, {'form': form})

這是一個非常簡單的例子,但是仍然可以看到,我們可以通過重寫類屬性(比如form_class)來自定義視圖,重寫類屬性的方法包括 URLconf 配置、創(chuàng)建子類并重寫一個或多個方法(或者兩者都有)。

裝飾類視圖


不僅可以通過 mixins 擴展類視圖,還可以使用裝飾器。由于類視圖不是函數(shù),對 as_view() 進行裝飾與對創(chuàng)建的子類進行裝飾的工作方式不同。

在URLconf中進行裝飾


裝飾類視圖最簡單的方法是裝飾 as_view() 方法的結(jié)果,最簡單的實現(xiàn)方法是在部署視圖的 URLconf 中。

from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView

from .views import VoteView

urlpatterns = [
    url(r'^about/$', login_required(TemplateView.as_view(template_name="secret.html"))),
    url(r'^vote/$', permission_required('polls.can_vote')(VoteView.as_view())),
]

這種方法對使用的實例進行裝飾。 如果希望每個視圖的實例都被裝飾,需要采取不同的方法。

裝飾類


如果需要裝飾類視圖的每個實例,則需要對類進行裝飾。可用通過裝飾類的 dispatch() 方法來實現(xiàn)對類進行裝飾。類方法與單獨函數(shù)不盡相同,因此不能只對類方法應(yīng)用一個函數(shù)裝飾器,而需要先將其轉(zhuǎn)換為一個方法裝飾器。method_decorator 裝飾器可以將一個函數(shù)裝飾器轉(zhuǎn)換為一個方法裝飾器,以使函數(shù)裝飾器可以用于實例方法中,例如:

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

class ProtectedView(TemplateView):
    template_name = 'secret.html'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(ProtectedView, self).dispatch(*args, **kwargs)

或者,可以更簡潔地通過裝飾類并將要裝飾的方法的名稱作為關(guān)鍵字參數(shù)進行傳遞:

@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

如果有一個在幾個位置使用的通用裝飾器集合,則可以定義一個裝飾器列表或元組來進行裝飾,而不用多次執(zhí)行method_decorator() 。下面例子中的兩個類是等效的:

decorators = [never_cache, login_required]

@method_decorator(decorators, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

@method_decorator(never_cache, name='dispatch')
@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

裝飾器將按照傳入到裝飾器的順序?qū)φ埱筮M行處理,上例中,never_cache() 將比 login_required() 先處理請求。

在這個例子中,每個 ProtectedView 的實例都將具有登錄保護。

注意:method_decorator 將*args**kwargs作為參數(shù)傳輸給類的裝飾方法。如果方法不接收兼容參數(shù)則可能會引發(fā) TypeError 異常。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 基于類的視圖 Django中的視圖是一個可調(diào)用對象,它接收一個請求然后返回一個響應(yīng)。這個可調(diào)用對象不僅僅限于函數(shù),...
    蘭山小亭閱讀 4,766評論 1 13
  • Django基于類的視圖 1.基于類的視圖簡介 基于類的視圖使用Python 對象實現(xiàn)視圖,它提供除函數(shù)視圖之外的...
    常大鵬閱讀 8,738評論 0 25
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,578評論 19 139
  • 10 構(gòu)建一個在線學(xué)習(xí)平臺 10.5 創(chuàng)建內(nèi)容管理系統(tǒng) 現(xiàn)在我們已經(jīng)創(chuàng)建了一個萬能的數(shù)據(jù)模型,接下來我們會創(chuàng)建一個...
    lakerszhy閱讀 1,712評論 0 4
  • 昨天半夜,女兒左翻翻右翻翻自己醒了。我也被她折騰醒了,抬眼看她,昏暗的光線下,她用小手撐著床顫顫巍巍地站了...
    ddb44dc2b8cc閱讀 409評論 0 0

友情鏈接更多精彩內(nèi)容