Django API 開發:視圖設置和路由

語言: CN / TW / HK

theme: devui-blue highlight: monokai-sublime


持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第 17 天,點擊查看活動詳情

前言

視圖集路由器是 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文件中。

```python

posts/serializers.py

from django.contrib.auth import get_user_model # new from rest_framework import serializers from .models import Post

class 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 引用用户模型,以便將其導入第一行。

```python

posts/views.py

from django.contrib.auth import get_user_model # new from rest_framework import generics

from .models import Post from .permissions import IsAuthorOrReadOnly from .serializers import PostSerializer, UserSerializer # new

class 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/

```python

posts/urls.py

from django.urls import path

from .views import UserList, UserDetail, PostList, PostDetail # new

urlpatterns = [ path('users/', UserList.as_view()), # new path('users//', UserDetail.as_view()), # new path('', PostList.as_view()), path('/', 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 文件中是這樣的。

```python

posts/views.py

from django.contrib.auth import get_user_model from rest_framework import viewsets # new

from .models import Post from .permissions import IsAuthorOrReadOnly from .serializers import PostSerializer, UserSerializer

class 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 。

Routers 路由

直接與視圖集一起使用,以自動為我們生成 URL 模式。 我們當前的 posts/urls.py 文件具有四個 URL模式:兩個用於博客文章,兩個用於用户。相反,我們可以為每個視圖集採用一條路由。 因此,使用兩個路由而不是四個 URL 模式。 聽起來更好吧?

Django REST Framework 具有兩個默認路由器:SimpleRouter 和 DefaultRouter 。 我們將使用 SimpleRouter,但也可以為更多高級功能創建自定義路由器。

更新後的代碼如下所示:

```python

posts/urls.py

from django.urls import path from rest_framework.routers import SimpleRouter

from .views import UserViewSet, PostViewSet

router = 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 複雜性的增加,如果您發現自己一遍又一遍地重複相同的端點模式,那麼請查看視圖集和路由器。