視圖集和路由器是 Django REST Framework 中的工具,可以加速 API 開發。 它們是視圖和 URL 之上的附加抽象層。 主要好處是單個視圖集可以替換多個相關視圖。 路由器可以自動為開發人員生成 URL。 在具有許多端點的大型項目中,這意味著開發人員必須編寫更少的代碼。 可以說,與一長串的單個視圖和 URL 相比,對於經驗豐富的開發人員而言,與少量視圖集和路由器組合相比,它更易於理解和推理。
在本章中,我們將向現有項目中添加兩個新的 API 端點,並了解如何從視圖和 URL 切換到視圖集和路由器可以用更少的代碼實現相同的功能。
當前,我們的項目中具有以下 API 端點。 它們都以 api/v1/
開頭,為簡潔起見,未顯示它們:
前兩個端點是我們創建的,而django-rest-auth提供了另外五個端點。 現在讓我們添加兩個其他端點,以列出所有用戶和單個用戶。 這是許多 API 中的常見功能,它將使我們更清楚地理解為什麼將我們的視圖和 URL 重構為視圖集和路由器是有意義的。
傳統 Django 具有內置的 User 模型類,我們已經在上一篇文章中使用了該類進行身份驗證。 因此,我們不需要創建新的數據庫模型。 相反,我們只需要連接新的端點即可。 此過程始終涉及以下三個步驟:
新增模型序列化器
新增每個端點視圖
新增每個端點的 URL 路由
從我們的序列化器開始。 我們需要導入 User 模型,然後創建一個使用它的 UserSerializer 類。 然後將其添加到我們現有的 posts/serializers.py
文件中。
# posts/serializers.pyfrom django.contrib.auth import get_user_model # new from rest_framework import serializersfrom .models import Postclass PostSerializer(serializers.ModelSerializer): class Meta: model = Post fields = ('id', 'author', 'title', 'body', 'created_at',)class UserSerializer(serializers.ModelSerializer): # new class Meta: model = get_user_model() fields = ('id', 'username',)
值得注意的是,雖然我們在這裡使用 get_user_model 來引用 User 模型,但實際上在 Django 中有3種不同的方式來引用 User 模型。
通過使用 get_user_model ,我們確保我們引用的是正確的用戶模型,無論是默認用戶模型還是新 Django 項目中經常定義的自定義用戶模型。
接下來,我們需要為每個端點定義視圖。 首先將 UserSerializer 添加到導入列表中。 然後創建列出所有用戶的 UserList 類和提供單個用戶詳細視圖的 UserDetail 類。 就像我們的帖子視圖一樣,我們可以在此處使用 ListCreateAPIView 和 RetrieveUpdateDestroyAPIView。
對於每個端點,我們只需要只讀或GET功能。 這意味著我們可以使用 ListAPIView 和 RetrieveUpdateDestroyAPIView 。 我們還需要通過 get_user_model 引用用戶模型,以便將其導入第一行。
# posts/views.pyfrom django.contrib.auth import get_user_model # new from rest_framework import genericsfrom .models import Postfrom .permissions import IsAuthorOrReadOnlyfrom .serializers import PostSerializer, UserSerializer # newclass PostList(generics.ListCreateAPIView): 0 queryset = Post.objects.all() serializer_class = PostSerializer class PostDetail(generics.RetrieveUpdateDestroyAPIView): permission_classes = (IsAuthorOrReadOnly,) queryset = Post.objects.all() serializer_class = PostSerializer class UserList(generics.ListCreateAPIView): # new queryset = get_user_model().objects.all() serializer_class = UserSerializer class UserDetail(generics.RetrieveUpdateDestroyAPIView): # new queryset = get_user_model().objects.all() serializer_class = UserSerializer
如果您注意到,這裡有很多重復。 Post 視圖和 User 視圖都具有完全相同的 queryset 和 serializer_class。
最後,我們有了 URL 路由。 確保導入新的 UserList 和 UserDetail 視圖。 然後,我們可以為每個用戶使用前綴 users/
。
# posts/urls.pyfrom django.urls import pathfrom .views import UserList, UserDetail, PostList, PostDetail # newurlpatterns = [ path('users/', UserList.as_view()), # new path('users/<int:pk>/', UserDetail.as_view()), # new path('', PostList.as_view()), path('<int:pk>/', PostDetail.as_view()),]
我們完成了。 確保本地服務器仍在運行,並跳至可浏覽的 API 以確認一切正常。
我們的用戶列表端點位於 http://127.0.0.1:8000/api/v1/users/
狀態代碼為 200 OK ,表示一切正常。 我們可以看到三個現有用戶。
每個用戶的主鍵上都有一個用戶詳細信息終結點。 因此,我們的超級用戶帳戶位於:http://127.0.0.1:8000/api/v1/users/1/
。
視圖集是一種將多個相關視圖的邏輯組合到單個類中的方法。 換句話說,一個視圖集可以替換多個視圖。 當前,我們有四個視圖:兩個用於博客帖子,兩個用於用戶。 相反,我們可以使用兩個視圖集來模仿相同的功能:一個用於博客文章,另一個用於用戶。
折衷方案是,對於不十分熟悉視圖集的其他開發人員,可讀性會有所下降。 所以這是一個權衡。當我們交換視圖集時,代碼在更新後的 posts/views.py
文件中是這樣的。
# posts/views.pyfrom django.contrib.auth import get_user_model from rest_framework import viewsets # newfrom .models import Postfrom .permissions import IsAuthorOrReadOnlyfrom .serializers import PostSerializer, UserSerializerclass PostViewSet(viewsets.ModelViewSet): # new permission_classes = (IsAuthorOrReadOnly,) queryset = Post.objects.all() serializer_class = PostSerializer class UserViewSet(viewsets.ModelViewSet): # new queryset = get_user_model().objects.all() serializer_class = UserSerializer
在頂部,而不是從 rest_framework 導入泛型,我們現在在第二行導入視圖集。 然後,我們使用ModelViewSet,它為我們提供了列表視圖和詳細信息視圖。 而且,我們不再需要像以前一樣為每個視圖重復相同的 queryset 和 serializer_class 。
直接與視圖集一起使用,以自動為我們生成 URL 模式。 我們當前的 posts/urls.py
文件具有四個 URL模式:兩個用於博客文章,兩個用於用戶。相反,我們可以為每個視圖集采用一條路由。 因此,使用兩個路由而不是四個 URL 模式。 聽起來更好吧?
Django REST Framework 具有兩個默認路由器:SimpleRouter 和 DefaultRouter 。 我們將使用 SimpleRouter,但也可以為更多高級功能創建自定義路由器。
更新後的代碼如下所示:
# posts/urls.pyfrom django.urls import pathfrom rest_framework.routers import SimpleRouterfrom .views import UserViewSet, PostViewSetrouter = SimpleRouter()router.register('users', UserViewSet, base_name='users') router.register('', PostViewSet, base_name='posts')urlpatterns = router.urls
在最上面一行,將導入 SimpleRouter 及其視圖。 路由器設置為 SimpleRouter,我們為用戶和帖子“注冊”每個視圖集。 最後,我們將 URL 設置為使用新路由器。
繼續並立即檢查我們的四個端點! 用戶列表是相同的。
但是,局部視圖有些不同。 現在它被稱為“用戶實例”,而不是“用戶詳細信息”,並且還有一個附加的“刪除”選項內置於ModelViewSet中。
可以自定義視圖集,但是一個重要的折衷是用視圖集編寫更少的代碼,這是默認設置,它可能需要一些其他配置才能完全匹配您想要的內容。
轉到發布列表,我們可以看到它是相同的:
重要的是,我們的權限仍然有效。 使用我們的 testuser2 帳戶登錄時,Post Instance 為只讀。
但是,如果我們使用超級用戶帳戶(該日志是單獨的博客文章的作者)登錄的,那麼我們將具有完整的讀寫-編輯-刪除權限。
視圖集和路由器是一種強大的抽象,可減少開發人員必須編寫的代碼量。 但是,這種簡潔性是以犧牲初始學習曲線為代價的。 最初幾次使用視圖集和路由器而不是視圖和 URL 模式會感到很奇怪。
最終,何時向項目添加視圖集和路由器的決定是相當主觀的。 一個好的經驗法則是從視圖和 URL 開始。 隨著 API 復雜性的增加,如果您發現自己一遍又一遍地重復相同的端點模式,那麼請查看視圖集和路由器。