Django REST framework API 指南(1):請求
Django REST framework API 指南(2):響應
Django REST framework API 指南(3):視圖
Django REST framework API 指南(4):通用視圖
Django REST framework API 指南(5):視圖集
Django REST framework API 指南(6):路由
Django REST framework API 指南(7):解析python
官方原文連接數據庫
基於類的視圖的一個主要優勢是它們容許你編寫可重複使用的行爲。 REST framework 經過提供大量預構建視圖來提供經常使用模式,從而充分利用了這一點。django
REST framework 提供的通用視圖容許您快速構建緊密映射到數據庫模型的 API 視圖。api
若是通用視圖不符合需求,可使用常規的 APIView
類,或者利用 mixin 特性和基類組合出可重用的視圖。緩存
一般,在使用通用視圖時,您須要繼承該視圖,並設置幾個類屬性。app
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,)
複製代碼
對於更復雜的狀況,您可能還想重寫視圖類中的各類方法。例如。ide
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsAdminUser,)
def list(self, request):
# 注意使用`get_queryset()`而不是`self.queryset`
queryset = self.get_queryset()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
複製代碼
對於很是簡單的狀況,您可能想要使用 .as_view()
方法來傳遞類屬性。例如,您的 URLconf 可能包含相似於如下條目的內容:post
url(r'^/users/', ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list')
複製代碼
直接在 URLconf 中設置相關屬性參數,這樣連視圖類都不用寫了。ui
GenericAPIView
類繼承於 REST framework 的 APIView
類,爲標準列表和詳細視圖添加了常見的行爲。url
內置的每個具體的通用視圖都是經過將 GenericAPIView
類和一個或多個 minxin 類相互結合來構建的。
如下屬性控制基本視圖行爲。
queryset
- 用於今後視圖返回對象的查詢集。一般,您必須設置此屬性,或覆蓋 get_queryset()
方法。若是你重寫了一個視圖方法,在視圖方法中,你應該調用 get_queryset()
而不是直接訪問這個屬性,這一點很重要!由於 REST 會在內部對 queryset
的結果進行緩存用於後續全部請求。serializer_class
- 用於驗證和反序列化輸入以及序列化輸出的序列化類。一般,您必須設置此屬性,或覆蓋 get_serializer_class()
方法。lookup_field
- 用於執行各個模型實例的對象查找的模型字段。默認爲 'pk'
。請注意,使用 hyperlinked API 時,若是須要使用自定義值,則須要確保 API 視圖和序列化類設置了 lookup field。lookup_url_kwarg
- 用於對象查找的 URL 關鍵字參數。URL conf 應該包含與此值相對應的關鍵字參數。若是未設置,則默認使用與 lookup_field
相同的值。關於後兩個參數,我這裏附上對象查詢的源碼你們就應該瞭解了。
省略部分代碼,方便理解
def get_object(self):
# 先獲取數據集
queryset = self.filter_queryset(self.get_queryset())
# 拿到查詢參數的 key
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
# 組裝成 {key:value} 的形式
filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
# 查詢
obj = get_object_or_404(queryset, **filter_kwargs)
# 最後返回
return obj
複製代碼
與列表視圖一塊兒使用時,如下屬性用於控制分頁。
pagination_class
- 對列表進行分頁時使用的分頁類。默認值與 DEFAULT_PAGINATION_CLASS
設置相同,即 rest_framework.pagination.PageNumberPagination
。設置 pagination_class = None
將禁用此視圖的分頁。filter_backends
- 用於過濾查詢集的過濾器類的列表。默認值與 DEFAULT_FILTER_BACKENDS
設置的值相同。get_queryset(self)
應該返回列表視圖的查詢集,並應該將其用做查看詳細視圖的基礎。默認返回由 queryset
屬性指定的查詢集。
應該始終使用此方法, 而不是直接訪問 self.queryset
,由於 REST 會在內部對 self.queryset
的結果進行緩存用於後續全部請求。
能夠覆蓋以提供動態行爲,例如針對不一樣用戶的請求返回不一樣的數據。
舉個栗子:
def get_queryset(self):
user = self.request.user
return user.accounts.all()
複製代碼
get_object(self)
應該返回詳細視圖的對象實例。默認使用 lookup_field
參數來過濾基本查詢集。
能夠覆蓋以提供更復雜的行爲,例如基於多個 URL kwarg 的對象查找。
舉個栗子:
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 不包含任何對象級權限,您能夠選擇排除 self.check_object_permissions
,並簡單地從 get_object_or_404
中查找返回對象。
filter_queryset(self, 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
複製代碼
get_serializer_class(self)
返回用於序列化的類。默認返回 serializer_class
屬性。
能夠被覆蓋以提供動態行爲,例如使用不一樣的序列化器進行讀寫操做,或爲不一樣類型的用戶提供不一樣的序列化器。
舉個栗子:
def get_serializer_class(self):
if self.request.user.is_staff:
return FullAccountSerializer
return BasicAccountSerializer
複製代碼
如下方法由 mixin 類提供,能夠很輕鬆的重寫對象的保存和刪除行爲。
perform_create(self, serializer)
- 保存新對象實例時由 CreateModelMixin
調用。perform_update(self, serializer)
- 在保存現有對象實例時由 UpdateModelMixin
調用。perform_destroy(self, instance)
- 刪除對象實例時由 DestroyModelMixin
調用。這些鉤子(hook)對設置請求中隱含的但不屬於請求數據的屬性特別有用。例如,您能夠根據請求用戶或基於 URL 關鍵字參數在對象上設置屬性。
def perform_create(self, serializer):
serializer.save(user=self.request.user)
複製代碼
這些覆蓋點對於添加保存對象以前或以後發生的行爲(如發送確認電子郵件或記錄更新)也特別有用。
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
編寫自定義視圖,則可能須要調用它們。
get_serializer_context(self)
- 返回包含應該提供給序列化的任何額外上下文的字典。默認包括 'request'
, 'view'
和 'format'
鍵。get_serializer(self, instance=None, data=None, many=False, partial=False)
- 返回一個序列化器實例。get_paginated_response(self, data)
- 返回分頁樣式的 Response
對象。paginate_queryset(self, queryset)
- 根據須要爲查詢集分頁,或者返回一個頁面對象;若是沒有爲該視圖配置分頁,則爲 None
。filter_queryset(self, queryset)
- 給定一個查詢集,使用過濾器進行過濾,返回一個新的查詢集。mixin 類用於提供基本視圖行爲的操做。請注意,mixin 類提供了操做方法,而不是直接定義處理方法,如 .get()
和 .post()
。這容許更靈活的行爲組合。
mixin 類能夠從 rest_framework.mixins
中導入。
提供一個 .list(request, *args, **kwargs)
方法,實現了列出一個查詢集。
若是查詢集已填充,則返回 200 OK
響應,並將 queryset 的序列化表示形式做爲響應的主體。響應數據能夠設置分頁。
提供 .create(request, *args, **kwargs)
方法,實現建立和保存新模型實例。
若是建立了一個對象,則會返回一個 201 Created
響應,並將該對象的序列化表示形式做爲響應的主體。若是表示包含名爲 url 的鍵,則響應的 Location
header 將填充該值。
若是爲建立對象提供的請求數據無效,則將返回 400 Bad Request
響應,並將錯誤細節做爲響應的主體。
提供 .retrieve(request, *args, **kwargs)
方法,該方法實如今響應中返回現有的模型實例。
若是能夠獲取對象,則返回 200 OK
響應,並將對象的序列化表示做爲響應的主體。不然,將返回一個 404 Not Found
。
提供 .update(request, *args, **kwargs)
方法,實現更新和保存現有模型實例。還提供了一個 .partial_update(request, *args, **kwargs)
方法,它與更新方法相似,只是更新的全部字段都是可選的。這容許支持 HTTP PATCH
請求。
若是成功更新對象,則返回 200 OK
響應,並將對象的序列化表示形式做爲響應的主體。
若是提供的用於更新對象的請求數據無效,則將返回 400 Bad Request
響應,並將錯誤細節做爲響應的主體。
提供一個 .destroy(request, *args, **kwargs)
方法,實現現有模型實例的刪除。
若是一個對象被刪除,則返回一個 204 No Content
,不然它將返回一個 404 Not Found
。
如下類是具體的通用視圖。一般狀況下,你應該都是使用的它們,除非須要高度的自定義行爲。
這些視圖類能夠從 rest_framework.generics
中導入。
僅用於建立實例。
提供一個 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
一般你會想使用現有的通用視圖,而後稍微定製一下行爲。若是您發現本身在多個地方重複使用了一些自定義行爲,則可能須要將行爲重構爲普通類,而後根據須要將其應用於任何視圖或視圖集。
例如,若是您須要根據 URL conf 中的多個字段查找對象,則能夠建立一個 mixin 類。
舉個栗子:
class MultipleFieldLookupMixin(object):
""" 將此 mixin 應用於任何視圖或視圖集以獲取多個字段過濾 基於`lookup_fields`屬性,而不是默認的單個字段過濾。 """
def get_object(self):
queryset = self.get_queryset() # 獲取基本的查詢集
queryset = self.filter_queryset(queryset) # 使用過濾器
filter = {}
for field in self.lookup_fields:
if self.kwargs[field]: # 忽略空字段
filter[field] = self.kwargs[field]
obj = get_object_or_404(queryset, **filter) # 查找對象
self.check_object_permissions(self.request, obj)
return obj
複製代碼
隨後能夠在須要應用自定義行爲的任什麼時候候,將該 mixin 應用於視圖或視圖集。
class RetrieveUserView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
lookup_fields = ('account', 'username')
複製代碼
若是您須要使用自定義行爲,那麼使用自定義 mixins 是一個不錯的選擇。
若是您在多個視圖中使用 mixin,您能夠進一步建立本身的一組基本視圖,而後在整個項目中使用它們。例如:
class BaseRetrieveView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
pass
class BaseRetrieveUpdateDestroyView(MultipleFieldLookupMixin, generics.RetrieveUpdateDestroyAPIView):
pass
複製代碼
若是自定義行爲始終須要在整個項目中的大量視圖中重複使用,那麼使用自定義基類是一個不錯的選擇。