Django的標(biāo)準(zhǔn) views...是為更快捷地使用常見的使用模式而開發(fā)的... 它們采用在view開發(fā)中找到的某些常見語法和模式,并對它們進(jìn)行抽象,以便你可以快速寫出數(shù)據(jù)的常見視圖,而無需重復(fù)自己。— Django 文檔
基于類的視圖的主要優(yōu)點之一是它們允許你組合一些可重用的行為。 REST framework通過提供許多預(yù)先構(gòu)建的視圖來提供常用的模式來利用這一優(yōu)點。
REST framework 提供的通用視圖允許您快速構(gòu)建與數(shù)據(jù)庫模型密切映射的API視圖。
如果通用視圖不適合你的API的需求,你可以選擇使用常規(guī) APIView 類,或重用通用視圖使用的mixins和基類來組成你自己的一組可重用的通用視圖。
通常在使用通用視圖時,你將覆蓋視圖,并設(shè)置多個類屬性。
from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from rest_framework import generics
from rest_framework.permissions import IsAdminUser
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsAdminUser, )
對于更復(fù)雜的情況,您可能還想覆蓋視圖類上的各種方法。比如:
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsAdminUser, )
def list(self, request):
# Note the use of `get_queryset()` instead of `self.queryset`
queryset = self.get_queryset()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
對于非常簡單的情況,你可能想使用 .as_view() 方法傳遞任何類屬性。 比如:你的URLconf可能包括類似以下條目:
url(r'^/users/', ListCreateAPIView.as_view\(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list')
此類擴展了REST框架的 APIView 類,為標(biāo)準(zhǔn)list和detail view 添加了通常需要的行為。
提供的每個具體通用視圖是通過將 GenericAPIView 與一個或多個mixin類組合來構(gòu)建的。
基本設(shè)置:
以下屬性控制著基本視圖的行為。
Pagination:
以下屬性用于在與列表視圖一起使用時控制分頁。
Filtering:
Base methods:
返回列表視圖中實用的查詢集,該查詢集還用作詳細(xì)視圖中的查找基礎(chǔ)。默認(rèn)返回由 queryset 屬性指定的查詢集。 這個方法應(yīng)該總是被調(diào)用而不是直接訪問 self.queryset ,因為 self.queryset 只會被計算一起,然后這些結(jié)果將為后續(xù)的請求緩存起來。 該方法可能會被重寫以提供動態(tài)行為,比如返回基于發(fā)出請求的用戶的結(jié)果集。
例如:
def get_queryset(self):
user = self.request.user
return user.accounts.all()
返回應(yīng)用于詳細(xì)視圖的對象實例。默認(rèn)使用 lookup_field 參數(shù)過濾基本的查詢集。
該方法可以被重寫以提供更復(fù)雜的行為,例如基于多個 URL 參數(shù)的對象查找。
例如:
def get_object(self):
queryset = self.get_queryset()
filter = {}
for field in self.multiple_lookup_fields:
filter[field] = self.kwargs[field]
obj = get_object_or_404(queryset, **filter)
self.check_object_permissions(self.request, obj)
return obj
請注意,如果你的API不包含任何對象級的權(quán)限控制,你可以選擇不執(zhí)行self.check_object_permissions,簡單的返回 get_object_or_404 查找的對象即可。
給定一個queryset,使用任何過濾器后端進(jìn)行過濾,返回一個新的queryset。
例如:
def filter_queryset(self, queryset):
filter_backends = (CategoryFilter, )
if 'geo_route' in self.request.query_params:
filter_backends = (GeoRouteFilter, CategoryFilter)
elif 'geo_point' in self.request.query_params:
filter_backends = (GeoPointFilter, CategoryFilter)
for backend in list(filter_backends):
queryset = backend().filter_queryset(self.request, queryset, view=self)
return queryset
返回應(yīng)用于序列化的類。默認(rèn)為返回 serializer_class 屬性的值。
可以被重寫以提供動態(tài)的行為,例如對于讀取和寫入操作使用不同的序列化器,或者為不同類型的用戶提供不同的序列化器。
例如:
def get_serializer_class(self\):
if self.request.user.is_staff:
return FullAccountSerializer
return BasicAccountSerializer
Save and deletion hooks:
以下方法由mixin類提供,并提供對象保存或刪除行為的簡單重寫。
這些鉤子對于設(shè)置請求中隱含的但不是請求數(shù)據(jù)的一部分的屬性特別有用。例如,你可以根據(jù)請求用戶或基于URL關(guān)鍵字參數(shù)在對象上設(shè)置屬性。
def perform_create(self, serializer):
serializer.save(user=self.request.user)
這些可重寫的關(guān)鍵點對于添加在保存對象之前或之后發(fā)生的行為(例如通過電子郵件發(fā)送確認(rèn)或記錄更新日志)也特別有用。
def perform_update(self, serializer):
instance = serializer.save()
send_email_confirmation(user=self.request.user, modified=instance)
你還可以使用這些鉤子通過拋出 ValidationError() 來提供額外的驗證。當(dāng)你需要在數(shù)據(jù)庫保存時應(yīng)用一些驗證邏輯時,這會很有用。 例如:
def perform_create(self, serializer):
queryset = SignupRequest.objects.filter(user=self.request.user)
if queryset.exists():
raise ValidationError('You have already signed up')
serializer.save(user=self.request.user)
注意: 這些方法替換了舊版本2.x中的 pre_save, post_save, pre_delete 和 post_delete 方法,這些方法不再可用。
其他方法:
你通常并不需要重寫以下方法,雖然在你使用 GenericAPIView 編寫自定義視圖的時候可能會調(diào)用它們。
Mixin 類提供用于提供基本視圖行為的操作。注意mixin類提供動作方法,而不是直接定義處理程序方法,例如 .get() 和 .post(), 這允許更靈活的行為組成。
Mixin 類可以從 rest_framework.mixins導(dǎo)入。
提供一個 .list(request, *args, **kwargs) 方法,實現(xiàn)列出結(jié)果集。
如果查詢集被填充了數(shù)據(jù),則返回 200 OK 響應(yīng),將查詢集的序列化表示作為響應(yīng)的主體。相應(yīng)數(shù)據(jù)可以任意分頁。
提供 .create(request, *args, **kwargs) 方法,實現(xiàn)創(chuàng)建和保存一個新的model實例。
如果創(chuàng)建了一個對象,這將返回一個 201 Created 響應(yīng),將該對象的序列化表示作為響應(yīng)的主體。如果序列化的表示中包含名為 url的鍵,則響應(yīng)的 Location 頭將填充該值。
如果為創(chuàng)建對象提供的請求數(shù)據(jù)無效,將返回 400 Bad Request,其中錯誤詳細(xì)信息作為響應(yīng)的正文。
提供一個 .retrieve(request, *args, **kwargs) 方法,實現(xiàn)返回響應(yīng)中現(xiàn)有模型的實例。
如果可以檢索對象,則返回 200 OK 響應(yīng),將該對象的序列化表示作為響應(yīng)的主體。否則將返回 404 Not Found。
提供 .update(request, *args, **kwargs) 方法,實現(xiàn)更新和保存現(xiàn)有模型實例。
同時還提供了一個 .partial_update(request, *args, **kwargs) 方法,這個方法和 update 方法類似,但更新的所有字段都是可選的。這允許支持 HTTP PATCH 請求。
如果一個對象被更新,這將返回一個 200 OK 響應(yīng),將對象的序列化表示作為響應(yīng)的主體。
如果為更新對象提供的請求數(shù)據(jù)無效,將返回一個 400 Bad Request 響應(yīng),錯誤詳細(xì)信息作為響應(yīng)的正文。
提供一個 .destroy(request, *args, **kwargs) 方法,實現(xiàn)刪除現(xiàn)有模型實例。
如果刪除對象,則返回 204 No Content 響應(yīng),否則返回 404 Not Found。
以下類是具體的通用視圖。這通常是你真正用到的那些,除非你需要深度定制的行為。
這些視圖類可以從 rest_framework.generics導(dǎo)入。
用于 僅創(chuàng)建 端點。
提供一個 post 方法處理程序。
擴展: GenericAPIView, CreateModelMixin
用于 只讀 端點以表示模型實例集合 。
提供一個 get 方法處理程序。
擴展: GenericAPIView, ListModelMixin
用于只讀 端點以表示單個模型實例。
提供一個 get 方法處理程序。
擴展: GenericAPIView, RetrieveModelMixin
用于只刪除端點以表示單個模型實例。
提供一個 delete 方法處理程序。
擴展: GenericAPIView, DestroyModelMixin
用于只更新端點以表示單個模型實例。
提供一個 put和patch方法處理程序。
擴展: GenericAPIView, UpdateModelMixin
用于讀寫端點以表示模型實例的集合。
提供一個 get 和 post 方法的處理程序。
擴展: GenericAPIView, ListModelMixin, CreateModelMixin
用于 讀取或更新 端點以表示 單個模型實例。
提供 get, put 和 patch 方法的處理程序。
擴展: GenericAPIView, RetrieveModelMixin, UpdateModelMixin
用于 讀取或刪除 端點以表示 單個模型實例。
提供 get 和 delete 方法的處理程序。
擴展: GenericAPIView, RetrieveModelMixin, DestroyModelMixin
用于 讀寫刪除 端點以表示 單個模型實例。
提供 get, put, patch 和 delete方法的處理程序。
擴展: GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin
通常你會想使用現(xiàn)有的通用視圖,但是使用一些簡單的自定義的行為。如果你發(fā)現(xiàn)自己在多個地方重復(fù)使用了一些自定義行為,你可能想將行為重構(gòu)為一個公共類,然后只需根據(jù)需要應(yīng)用到任何視圖或視圖集。
例如,如果你需要基于 URL conf中的多個字段查找對象,則可以創(chuàng)建一個如下所示的 mixin類:
class MultipleFieldLookupMixin(object):
"""
Apply this mixin to any view or viewset to get multiple field filtering
based on a `lookup_fields` attribute, instead of the default single field filtering.
"""
def get_object(self):
queryset = self.get_queryset() # 獲取基本的queryset
queryset = self.filter_queryset(queryset) # 應(yīng)用任何過濾器后端
filter = {}
for field in self.lookup_fields:
if self.kwargs[field]: # Ignore empty fields.
filter[field] = self.kwargs[field]
return get_object_or_404(queryset, **filter) # 查找對象
然后,你可以在需要應(yīng)用自定義行為時隨時將此mixin類應(yīng)用于視圖或視圖集。
class RetrieveUserView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
lookup_fields = ('account', 'username')
如果你需要使用自定義行為,那么使用自定義mixin是一個不錯的選擇。
如果你在多個視圖中使用mixin,你可以進(jìn)一步創(chuàng)建你自己的一組基本視圖,然后可以在整個項目中使用。舉個例子:
class BaseRetrieveView(MultipleFieldLookupMixin,
generics.RetrieveAPIView):
pass
class BaseRetrieveUpdateDestroyView(MultipleFieldLookupMixin,
generics.RetrieveUpdateDestroyAPIView):
pass
如果你的自定義行為始終需要在整個項目中的大量視圖中重復(fù),則使用自定義基類是一個不錯的選擇。
在3.0版本之前,REST framework mixins 將 PUT 視為更新或創(chuàng)建操作,具體取決于對象是否已存在。
允許 PUT 作為創(chuàng)建操作是有問題的,因為它必然會暴露關(guān)于對象的存在與不存在的信息。同樣不明顯的是,透明地允許重新創(chuàng)建以前刪除的實例是比簡單地返回404響應(yīng)更好的默認(rèn)行為。
兩種形式 "PUT as 404" 和 "PUT as create" 可以在不同的情況下有效,但從3.0版本起,我們現(xiàn)在使用 404作為默認(rèn)值,因為它更簡單和更明顯。
如果你需要通用的 PUT-as-create行為,你可能想要包括像 這個AllowPUTAsCreateMixin 類 一樣的mixin在你的視圖里。
以下第三方包提供了其他通用視圖實現(xiàn)。
The django-rest-framework-bulk package 包實現(xiàn)通用視圖mixins以及一些常見的具體通用視圖,以允許通過API請求應(yīng)用批量操作。
Django Rest Multiple Models 提供了通過單個API請求發(fā)送多個序列化模型和/或者查詢集的通用視圖(和mixin)。
更多建議: