第 5 篇:用視圖集,簡化你的代碼


作者:HelloGitHub-追夢人物

在 RESTful 架構中,對資源的常規操作無非就是查詢、新增、修改、刪除等這么幾種。為此,django-rest-framework 分別提供了對應通用類視圖函數。但是,如果對同一個資源的不同操作邏輯分散在各個視圖函數中,從邏輯上來說不太合理,實際中管理起來也不是很方便,還會產生很多重復性的代碼。因此,django-rest-framework 引入了視圖集(Viewsets),把對同一個資源的不同操作,集中到一個類中。同樣的,針對 Web 開發中的常見邏輯,django-rest-framework 也提供了通用視圖集,進一步簡化開發工作。

使用視圖集的一個更大的好處,就是可以配合 django-rest-framework 提供的路由器(router),自動生成 API 的 URL,不需要我們再手工將 URL 模式和視圖函數綁定了。所以大部分情況下,即使對資源只有一種操作,我們一般也會使用視圖集。

先來看看博客首頁文章列表視圖集的代碼:

blog/views.py

from rest_framework import viewsets
from rest_framework import mixins

class PostViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    serializer_class = PostListSerializer
    queryset = Post.objects.all()
    pagination_class = PageNumberPagination
    permission_classes = [AllowAny]

所有視圖集都要繼承視圖集的基類。視圖集也有 2 個基類:ViewSetGenericViewSet,前者是最基本的視圖集類,后者拓展自前者,拓展了很多 Web 開發中的通用邏輯。

要注意一點的是,視圖集基類提供的是除資源操作以外的通用邏輯(例如 HTTP 請求預處理、HTTP 響應后處理、認證、鑒權等),而對於資源的操作(如序列化、更新、刪除資源等)則放在相應的 Mixin 混入類里。django-rest-framework 提供了資源操作的 5 個混入類,分別對應資源的創建、查詢、更新、刪除。

  • CreateModelMixin

    提供 create 方法用於創建資源

  • ListModelMixin 和 RetrieveModelMixin

    提供 list 和 retrieve,分別用於獲取資源列表和單個資源

  • UpdateModelMixin

    提供 update 方法用於更新資源

  • DestroyModelMixin

    提供 destroy 方法用於刪除資源

此外,create、list、retrieve、update、destroy 的方法名會被映射為對應的 action,稱為對資源操作的一個動作。前面說到視圖集的一個最大好處就是可以使用路由器(router)自動生成 URL 模式。URL 正是根據 action 的類型來生成的,后面我們會具體說到。

好了,視圖集已經創建完畢,接下來我們從視圖集生成視圖函數,並綁定 URL。

blog/views.py

index = PostViewSet.as_view({'get': 'list'})
blog/urls.py

app_name = "blog"
urlpatterns = [
    # ...
    # path("api/index/", views.IndexPostListAPIView.as_view()),
    path("api/index/", index),
]

等等,不是說視圖集的一個好處是使用路由器自動生成 URL 模式嗎?為什么還要手工創建視圖函數,然后綁定 URL?

別急,這里只是演示一下如何從視圖集生成視圖函數並綁定 URL,這樣能夠幫助你更好地理解視圖集的工作方式。事實上,使用路由器自動生成 URL 模式時,路由器內部就是采用了和上面手工生成視圖函數並綁定 URL 一樣的方式。

路由器的使用非常簡單,我們在 初始化 RESTful API 風格的博客系統 中引入了 DefaultRouter 以開啟 API 交互后台,DefaultRouter 實例化時默認幫我們注冊了一個 API 交互后台的根視圖,現在要注冊一個新的視圖,調用其 register 方法就可以了:

blogproject/urls.py

from blog.views import PostViewSet
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'posts', PostViewSet, basename='post')

Django-rest-framework 提供 SimpleRouterDefaultRouter 兩個路由器類,后者是對前者的拓展,因此通常情況下都使用后者。DefaultRouter 增加了一個 api 的根路由,訪問根路由的 URL 就可以看到其他注冊的全部 api 路由,一會兒我們將會看到具體的效果。

視圖集自動生成 URL 模式非常簡單,只需實例化一個路由器,然后調用其 register 方法,這個方法接收 3 個參數,第一個參數是 URL 前綴,所有從注冊的視圖集生成的 URL 都會帶有這個前綴。第二個參數就是視圖集,第三個參數 basename 用於指定視圖集生成的視圖函數名的前綴。在 django 的 URL 中,一條路由通常由 URL 模式,對應的視圖函數和視圖函數名組成。視圖函數名的作用主要用於解析視圖函數所對應的 URL。視圖集最終會被轉為多個視圖函數,那么這個視圖函數的名字是什么呢?django-rest-framework 的默認生成規則是 basename-action。

例如這里 basename='post',列出資源列表的 action 為 list(見上一篇教程中關於 action 的講解),所以生成的獲取文章資源列表的視圖函數名為 post-list,使用 reverse('post-list') 就可以解析出獲取文章資源列表的 API(URL)。

basename 可以不指定,django-rest-framework 會自動從視圖集 get_queryset 方法返回的結果所關聯的 model 獲取一個默認值,其值為 model 名小寫。不過,根據 Python 之禪,顯式優於隱式,因此即使你設置的 basename 和 django-rest-framework 默認生成的一樣,也比不指定要好。

剛才說了,我們使用 DefaultRouter 這個路由器,它會自動幫我們注冊一個根路由,來看看根路由下有什么。

運行開發服務器,訪問 http://127.0.0.1:8000/api/,界面如下:

django-rest-framework 為我們自動生成了 API 交互后台,在這個界面中可以和我們創建的 API 交互,非常方便。API 交互后台首頁是所有注冊的視圖集對應的 URL。目前只有一條 /api/posts/,點擊超鏈接進去,可以看到 /api/posts/ 的返回結果,即全部文章列表。

但是,目前我們的 api 一股腦將全部文章列表的返回了。但是我們的博客文章列表是有分頁功能的,接下來我們就使用 django-rest-framework 提供的分頁輔助類,一行代碼就可以完成分頁功能。


關注公眾號加入交流群


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM