W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
基于類的視圖提供另一種將視圖實現(xiàn)為 Python 對象而不是函數(shù)的方法。它們不能替代基于函數(shù)的視圖,但與基于函數(shù)的視圖相比,它們是有某些不同和優(yōu)勢的。
GET
?, ?POST
?等)關聯(lián)的代碼組織能通過單獨的方法替代條件分支來解決。mixins
?多重繼承)可用于將代碼分解為可重用組件。一開始,這里只有視圖函數(shù),Django 傳遞 ?HttpRequest
?函數(shù)并預期返回一個 ?HttpResponse
?。這是 Django 能提供的范圍。
早期人們就發(fā)現(xiàn)在視圖開發(fā)過程中有常見的約定和模式。引入了基于函數(shù)的通用視圖為這些常見情況抽象這些模式和簡單視圖的開發(fā)。
基于函數(shù)的通用視圖的問題是即便它們可以很好的處理簡單案例,但除了一些配置選項之外,沒辦法擴展或自定義它們,這樣就限制了它們在實際應用中用途。
創(chuàng)建基于類的通用視圖與基于函數(shù)的通用視圖具有相同的目標,那就是使視圖開發(fā)更容易。然而,通過使用 mixins 實現(xiàn)解決方案的方式提供了一個工具包,使基于類的通用視圖比基于函數(shù)的通用視圖更靈活,更有擴展性。
如果你之前有嘗試過基于函數(shù)的通用視圖并發(fā)現(xiàn)了它的不足之處,那么你不應該認為基于類的通用視圖只是基于類的等效視圖,而是作為一種新的方法來解決通用視圖要解決的原始問題。
為了獲得最大的靈活性,Django 使用基礎類和?mixins
?的工具包來構建通用視圖,因此在默認方法實現(xiàn)和屬性的形式中有很多鉤子,你在最簡單的用例中不太可能涉及到這些鉤子。比如,不要將你限制為 ?form_class
?的基于類的屬性,使用 ?get_form
?方法來實現(xiàn),使用 ?get_form
?方法,它調(diào)用 ?get_form_class
?方法,在默認實現(xiàn)里只返回類的 ?form_class
?屬性。這給你一些選項來指定使用的表單,從簡單屬性到完全動態(tài)的可調(diào)用屬性。這些選項看起來增加了復雜度,但沒有它們,會限制更高級的設計。
本質(zhì)上來說,基于類的視圖允許你使用不同的類實例方法響應不同 HTTP 請求方法,而不是在單個視圖函數(shù)里使用有條件分支的代碼。
因此在視圖函數(shù)里處理 HTTP ?GET
?的代碼應該像下面這樣:
from django.http import HttpResponse
def my_view(request):
if request.method == 'GET':
# <view logic>
return HttpResponse('result')
而在基于類的視圖里,會變成:
from django.http import HttpResponse
from django.views import View
class MyView(View):
def get(self, request):
# <view logic>
return HttpResponse('result')
因為 Django 的 URL 解析器期望發(fā)送請求和相關參數(shù)來調(diào)動函數(shù)而不是類,基于類的視圖有一個 ?as_view()
? 類方法,當一個請求到達的 URL 被關聯(lián)模式匹配時,這個類方法返回一個函數(shù)。這個函數(shù)創(chuàng)建一個類的實例,調(diào)用 ?setup()
? 初始化它的屬性,然后調(diào)用 ?dispatch()
? 方法。 ?dispatch
?觀察請求并決定它是 ?GET
?和 ?POST
?,等等。如果它被定義,那么依靠請求來匹配方法,否則會引發(fā) ?HttpResponseNotAllowed
?。
# urls.py
from django.urls import path
from myapp.views import MyView
urlpatterns = [
path('about/', MyView.as_view()),
]
值得注意的是,你的方法返回值和基于函數(shù)的視圖返回值是相同的,既某種形式的 ?HttpResponse
?。這意味著 http 快捷函數(shù) 或 ?TemplateResponse
?對象可以使用基于類里的視圖。
雖然基于類的最小視圖不需要任何類屬性來執(zhí)行任務,類屬性在很多基于類的始終很常見,這里有兩種方法來配置或設置類屬性。
第一種是子類化標準 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 中將配置類屬性作為參數(shù)來調(diào)用 ?as_view()
?
urlpatterns = [
path('about/', GreetingView.as_view(greeting="G'day")),
]
注解:當你的類為發(fā)送給它的每個請求實例化時,通過 ?as_view()
? 入口點設置的類屬性在導入 URLs 的時候只配置一次。
?Mixins
?是一個多繼承表單,其中可組合多個父類的行為和屬性。
舉例,在通用基于類的視圖中,名為 ?TemplateResponseMixin
?的 ?mixin
?的首要目的是定義方法 ?render_to_response()
?。當與視圖的基類行為結合使用時,結果是一個 ?TemplateView
?類,它將請求分派到適當?shù)钠ヅ浞椒ǎㄔ谝晥D基類中定義的行為),并且具有 ?render_to_response()
? 方法,該方法使用 ?template_name
?屬性返回一個 ?TemplateResponse
?對象(在 ?TemplateResponseMixin
?中定義的行為)。
?Mixins
?是在多個類中重用代碼的絕佳方法,但它們需要一些代價。代碼分散在 ?Mixins
?中的越多,理解子類并知道它到底在做什么就越困難,而且如果你正在子類化具有深繼承樹的東西,那么就越難知道要從哪個 ?mixns
?的方法中來覆蓋它。
也需要注意你只能從一個通用視圖繼承——只有一個父類可以繼承自 ?View
?,剩余的(如果有的話)應該繼承自 ?mixins
?。試著從更多的繼承自 ?View
?的類繼承的話——例如試著在列表頂部使用表單并組合 ?ListView
?——將無法按照預期工作。
處理表單的基于函數(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})
類似的基于類的視圖可能看起來像這樣:
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
?配置或者子類化和重寫一個或多個方法(或者兩種都可以)。
基于類的視圖的擴展不僅限于使用 ?mixins
?,你也可以使用裝飾器。因為基于類的視圖不是函數(shù),所以根據(jù)你是使用 ?as_view()
? 還是創(chuàng)建子類,裝飾它們的工作方式會有不同。
可以通過裝飾 ?as_view()
? 方法的結果來調(diào)整基于類的視圖。最簡單的方法是在你部署視圖的 ?URLconf
?中執(zhí)行此操作:
from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView
from .views import VoteView
urlpatterns = [
path('about/', login_required(TemplateView.as_view(template_name="secret.html"))),
path('vote/', permission_required('polls.can_vote')(VoteView.as_view())),
]
這個方式在每個基本實例上應用裝飾器。如果你想裝飾視圖的每個實例,你需要采用不同方式。
裝飾基于類的視圖的每個實例,你需要裝飾類定義本身。為此,你可以將裝飾器應用到類的 ?dispatch()
? 方法。
類上的方法與獨立函數(shù)完全不同,因此你不能應用函數(shù)裝飾器到方法上——你需要先將它轉(zhuǎn)換為方法裝飾器。?method_decorator
? 裝飾器轉(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().dispatch(*args, **kwargs)
或者,更簡潔的說,你可以用裝飾類來代替,并作為關鍵參數(shù) ?name
?傳遞要被裝飾的方法名:
@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
template_name = 'secret.html'
如果你在一些地方使用了常見的裝飾器,你可以定義一個裝飾器列表或元組,并使用它而不是多次調(diào)用 ?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'
裝飾器將按照它們傳遞給裝飾器的順序來處理請求。在這個例子里,?never_cache()
? 將在 ?login_required()
? 之前處理請求。
在這個例子里,?ProtectedView
?的每一個實例將被登錄保護。盡管這些例子使用 ?login_required
? ,但可以使用 ?LoginRequiredMixin
?獲得同樣的行為。
注解:?method_decorator
?將? *args
? 和 ?**kwargs
? 作為參數(shù)傳遞給類上的裝飾方法。如果你的方法不接受兼容參數(shù)集合,它會引發(fā) ?TypeError
?錯誤。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: