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):解析
檢視集
在路由決定了哪個控制器用於請求後,控制器負責理解請求併產生適當的輸出。
— Ruby on Rails 文件
Django REST framework 允許將一組相關檢視的邏輯組合到一個稱為 ViewSet
的類中。在其他框架中,您可能會發現概念上類似的實現,名為 “Resources” 或 “Controllers” 。
ViewSet
類只是一種基於類的 View,它不提供任何處理方法,如 .get()
或 .post()
,而是提供諸如 .list()
和 .create()
之類的操作。
ViewSet
只在用 .as_view()
方法繫結到最終化檢視時做一些相應操作。
通常,不是在 urlconf 中的檢視集中明確註冊檢視,而是使用路由器類註冊檢視集,這會自動為您確定 urlconf。
舉個例子
定義一個簡單的檢視集,可以用來列出或檢索系統中的所有使用者。
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from myapps.serializers import UserSerializer
from rest_framework import viewsets
from rest_framework.response import Response
class UserViewSet(viewsets.ViewSet):
def list(self, request):
queryset = User.objects.all()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
queryset = User.objects.all()
user = get_object_or_404(queryset, pk=pk)
serializer = UserSerializer(user)
return Response(serializer.data)
複製程式碼
如果需要,可以將這個檢視集合成兩個單獨的檢視,如下所示:
user_list = UserViewSet.as_view({`get`: `list`})
user_detail = UserViewSet.as_view({`get`: `retrieve`})
複製程式碼
通常情況下,我們不會這樣做,而是用路由器註冊檢視集,並允許自動生成 urlconf。
from myapp.views import UserViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r`users`, UserViewSet, base_name=`user`)
urlpatterns = router.urls
複製程式碼
不用自己編寫檢視集,通常使用預設提供的現有基類。例如:
class UserViewSet(viewsets.ModelViewSet):
"""
用於檢視和編輯使用者例項的檢視。
"""
serializer_class = UserSerializer
queryset = User.objects.all()
複製程式碼
使用 ViewSet
類比使用 View 類有兩個主要優點。
- 重複的邏輯可以合併成一個類。在上面的例子中,我們只需要指定一次查詢集,它將在多個檢視中使用。
- 通過使用 routers,我們不再需要處理自己的 URL 配置。
這兩者各有優缺點。使用常規檢視和 URL 配置檔案更加明確,併為您提供更多控制。如果想要更快速的開發出一個應用,或者需要使大型 API 的 URL 配置始終保持一致,檢視集會非常有用。
操作檢視集
REST framework 中包含的預設 routes 將為一組標準的 create / retrieve / update / destroy 風格 action 提供路由,如下所示:
class UserViewSet(viewsets.ViewSet):
"""
這些方法將由路由器負責處理。
如果要使用字尾,請確保加上 `format = None` 關鍵字引數
"""
def list(self, request):
pass
def create(self, request):
pass
def retrieve(self, request, pk=None):
pass
def update(self, request, pk=None):
pass
def partial_update(self, request, pk=None):
pass
def destroy(self, request, pk=None):
pass
複製程式碼
在排程期間,當前 action 的名稱可以通過 .action
屬性獲得。您可以檢查 .action
以根據當前 action 調整行為。
例如,您可以將許可權限制為只有 admin 才能訪問 list
以外的其他 action,如下所示:
def get_permissions(self):
"""
例項化並返回此檢視所需的許可權列表。
"""
if self.action == `list`:
permission_classes = [IsAuthenticated]
else:
permission_classes = [IsAdmin]
return [permission() for permission in permission_classes]
複製程式碼
標記額外的路由行為
如果需要路由特定方法,則可以用 @detail_route
或 @list_route
裝飾器進行修飾。
@detail_route
裝飾器在其 URL 模式中包含 pk
,用於支援需要獲取單個例項的方法。@list_route
修飾器適用於在物件列表上操作的方法。
舉個例子:
from django.contrib.auth.models import User
from rest_framework import status
from rest_framework import viewsets
from rest_framework.decorators import detail_route, list_route
from rest_framework.response import Response
from myapp.serializers import UserSerializer, PasswordSerializer
class UserViewSet(viewsets.ModelViewSet):
"""
提供標準操作的檢視集
"""
queryset = User.objects.all()
serializer_class = UserSerializer
@detail_route(methods=[`post`])
def set_password(self, request, pk=None):
user = self.get_object()
serializer = PasswordSerializer(data=request.data)
if serializer.is_valid():
user.set_password(serializer.data[`password`])
user.save()
return Response({`status`: `password set`})
else:
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
@list_route()
def recent_users(self, request):
recent_users = User.objects.all().order(`-last_login`)
page = self.paginate_queryset(recent_users)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(recent_users, many=True)
return Response(serializer.data)
複製程式碼
另外,裝飾器可以為路由檢視設定額外的引數。例如…
@detail_route(methods=[`post`], permission_classes=[IsAdminOrIsSelf])
def set_password(self, request, pk=None):
...
複製程式碼
這些裝飾器預設路由 GET
請求,但也可以使用 methods
引數接受其他 HTTP 方法。例如:
@detail_route(methods=[`post`, `delete`])
def unset_password(self, request, pk=None):
...
複製程式碼
這兩個新操作將在 urls ^users/{pk}/set_password/$
和 ^users/{pk}/unset_password/$
上。
action 跳轉
如果你需要獲取 action 的 URL ,請使用 .reverse_action()
方法。這是 .reverse()
的一個便捷包裝,它會自動傳遞檢視的請求物件,並將 url_name
與 .basename
屬性掛接。
請注意,basename
是在 ViewSet
註冊過程中由路由器提供的。如果您不使用路由器,則必須提供.as_view()
方法的 basename
引數。
使用上一節中的示例:
>>> view.reverse_action(`set-password`, args=[`1`])
`http://localhost:8000/api/users/1/set_password`
複製程式碼
url_name
引數應該與 @list_route
和 @detail_route
裝飾器的相同引數匹配。另外,這可以用來反轉預設 list
和 detail
路由。
API 參考
ViewSet
ViewSet
類繼承自 APIView
。您可以使用任何標準屬性(如 permission_classes
,authentication_classes
)來控制檢視上的 API 策略。
ViewSet
類不提供任何 action 的實現。為了使用 ViewSet
類,必須繼承該類並明確定義 action 實現。
GenericViewSet
GenericViewSet
類繼承自 GenericAPIView
,並提供預設的 get_object
,get_queryset
方法和其他通用檢視基礎行為,但預設情況下不包含任何操作。
為了使用 GenericViewSet
類,必須繼承該類並混合所需的 mixin 類,或明確定義操作實現。
ModelViewSet
ModelViewSet
類繼承自 GenericAPIView
,並通過混合各種 mixin 類的行為來包含各種操作的實現。
ModelViewSet
提供的操作有 .list()
, .retrieve()
, .create()
, .update()
, .partial_update()
, 和 .destroy()
。
舉個例子:
由於 ModelViewSet
類繼承自 GenericAPIView
,因此通常需要提供至少 queryset
和 serializer_class
屬性。例如:
class AccountViewSet(viewsets.ModelViewSet):
"""
用於檢視和編輯 Account
"""
queryset = Account.objects.all()
serializer_class = AccountSerializer
permission_classes = [IsAccountAdminOrReadOnly]
複製程式碼
請注意,您可以覆蓋 GenericAPIView
提供的任何標準屬性或方法。例如,要動態確定它應該操作的查詢集的ViewSet
,可以這樣做:
class AccountViewSet(viewsets.ModelViewSet):
"""
A simple ViewSet for viewing and editing the accounts
associated with the user.
"""
serializer_class = AccountSerializer
permission_classes = [IsAccountAdminOrReadOnly]
def get_queryset(self):
return self.request.user.accounts.all()
複製程式碼
但請注意,從 ViewSet
中刪除 queryset
屬性後,任何關聯的 router 將無法自動匯出模型的 base_name
,因此您必須將 base_name
kwarg 指定為 router 註冊的一部分。
還要注意,雖然這個類預設提供了完整的 create / list / retrieve / update / destroy 操作集,但您可以通過使用標準許可權類來限制可用操作。
ReadOnlyModelViewSet
ReadOnlyModelViewSet
類也從 GenericAPIView
繼承。與 ModelViewSet
一樣,它也包含各種操作的實現,但與 ModelViewSet
不同的是它只提供 “只讀” 操作,.list()
和 .retrieve()
。
舉個例子:
與 ModelViewSet
一樣,您通常需要提供至少 queryset
和 serializer_class
屬性。例如:
class AccountViewSet(viewsets.ReadOnlyModelViewSet):
"""
A simple ViewSet for viewing accounts.
"""
queryset = Account.objects.all()
serializer_class = AccountSerializer
複製程式碼
同樣,與 ModelViewSet
一樣,您可以覆蓋GenericAPIView
可用的任何標準屬性和方法。
自定義檢視集基類
您可能需要使用沒有完整 ModelViewSet
操作集的自定義 ViewSet
類,或其他自定義行為。
舉個例子:
要建立提供 create
, list
和 retrieve
操作的基本檢視集類,請從 GenericViewSet
繼承,並混合(mixin )所需的操作:
from rest_framework import mixins
class CreateListRetrieveViewSet(mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
viewsets.GenericViewSet):
"""
A viewset that provides `retrieve`, `create`, and `list` actions.
To use it, override the class and set the `.queryset` and
`.serializer_class` attributes.
"""
pass
複製程式碼
通過建立自己的基本 ViewSet
類,能夠提供可在 API 中的多個檢視集中重用的常見行為。