新聞中心
基于類的視圖提供另一種將視圖實現(xiàn)為 Python 對象而不是函數(shù)的方法。它們不能替代基于函數(shù)的視圖,但與基于函數(shù)的視圖相比,它們是有某些不同和優(yōu)勢的。

創(chuàng)新互聯(lián)建站提供高防服務器、云服務器、香港服務器、服務器托管等
- 與特定的 HTTP 方法(?
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 ?方法,它調用 ?get_form_class ?方法,在默認實現(xiàn)里只返回類的 ?form_class ?屬性。這給你一些選項來指定使用的表單,從簡單屬性到完全動態(tài)的可調用屬性。這些選項看起來增加了復雜度,但沒有它們,會限制更高級的設計。
使用基于類的視圖
本質上來說,基于類的視圖允許你使用不同的類實例方法響應不同 HTTP 請求方法,而不是在單個視圖函數(shù)里使用有條件分支的代碼。
因此在視圖函數(shù)里處理 HTTP ?GET ?的代碼應該像下面這樣:
from django.http import HttpResponse
def my_view(request):
if request.method == 'GET':
#
return HttpResponse('result')
而在基于類的視圖里,會變成:
from django.http import HttpResponse
from django.views import View
class MyView(View):
def get(self, request):
#
return HttpResponse('result')
因為 Django 的 URL 解析器期望發(fā)送請求和相關參數(shù)來調動函數(shù)而不是類,基于類的視圖有一個 ?as_view()? 類方法,當一個請求到達的 URL 被關聯(lián)模式匹配時,這個類方法返回一個函數(shù)。這個函數(shù)創(chuàng)建一個類的實例,調用 ?setup()? 初始化它的屬性,然后調用 ?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ù)來調用 ?as_view()?
urlpatterns = [
path('about/', GreetingView.as_view(greeting="G'day")),
]
注解:當你的類為發(fā)送給它的每個請求實例化時,通過 ?as_view()? 入口點設置的類屬性在導入 URLs 的時候只配置一次。
使用mixins
?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():
#
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():
#
return HttpResponseRedirect('/success/')
return render(request, self.template_name, {'form': form})
這是一個很小的案例,但你可以看到你可以選擇通過覆蓋類的任何屬性來自定義這個視圖,比如 ?form_class ?,通過 ?URLconf ?配置或者子類化和重寫一個或多個方法(或者兩種都可以)。
裝飾基于類的視圖
基于類的視圖的擴展不僅限于使用 ?mixins ?,你也可以使用裝飾器。因為基于類的視圖不是函數(shù),所以根據(jù)你是使用 ?as_view()? 還是創(chuàng)建子類,裝飾它們的工作方式會有不同。
在 URLconf 中裝飾
可以通過裝飾 ?as_view()? 方法的結果來調整基于類的視圖。最簡單的方法是在你部署視圖的 ?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ù)裝飾器到方法上——你需要先將它轉換為方法裝飾器。?method_decorator? 裝飾器轉換函數(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'
如果你在一些地方使用了常見的裝飾器,你可以定義一個裝飾器列表或元組,并使用它而不是多次調用 ?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 ?錯誤。
當前題目:創(chuàng)新互聯(lián)Django4.0教程:Django4.0基于類的視圖-使用
URL分享:http://m.fisionsoft.com.cn/article/cosehpi.html


咨詢
建站咨詢
