第 5 篇:用檢視集,簡化你的程式碼
阿新 • • 發佈:2020-05-15
![](https://img2020.cnblogs.com/blog/759200/202004/759200-20200415161158343-1662112908.jpg)
作者:[HelloGitHub-追夢人物](https://www.zmrenwu.com)
在 RESTful 架構中,對資源的常規操作無非就是查詢、新增、修改、刪除等這麼幾種。為此,django-rest-framework 分別提供了對應通用類檢視函式。但是,如果對同一個資源的不同操作邏輯分散在各個檢視函式中,從邏輯上來說不太合理,實際中管理起來也不是很方便,還會產生很多重複性的程式碼。因此,django-rest-framework 引入了檢視集(Viewsets),把對同一個資源的不同操作,集中到一個類中。同樣的,針對 Web 開發中的常見邏輯,django-rest-framework 也提供了通用檢視集,進一步簡化開發工作。
使用檢視集的一個更大的好處,就是可以配合 django-rest-framework 提供的路由器(router),自動生成 API 的 URL,不需要我們再手工將 URL 模式和檢視函式綁定了。所以大部分情況下,即使對資源只有一種操作,我們一般也會使用檢視集。
先來看看部落格首頁文章列表檢視集的程式碼:
```python
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 個基類:`ViewSet` 和 `GenericViewSet`,前者是最基本的檢視集類,後者拓展自前者,拓展了很多 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。
```python
blog/views.py
index = PostViewSet.as_view({'get': 'list'})
```
```python
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 風格的部落格系統](https://www.zmrenwu.com/courses/django-rest-framework-tutorial/materials/92/) 中引入了 DefaultRouter 以開啟 API 互動後臺,DefaultRouter 例項化時預設幫我們註冊了一個 API 互動後臺的根檢視,現在要註冊一個新的檢視,呼叫其 `register` 方法就可以了:
```python
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 提供 `SimpleRouter` 和 `DefaultRouter` 兩個路由器類,後者是對前者的拓展,因此通常情況下都使用後者。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/,介面如下:
![](https://img2020.cnblogs.com/blog/759200/202005/759200-20200514222618348-429957972.png)
django-rest-framework 為我們自動生成了 API 互動後臺,在這個介面中可以和我們建立的 API 互動,非常方便。API 互動後臺首頁是所有註冊的檢視集對應的 URL。目前只有一條 /api/posts/,點選超連結進去,可以看到 /api/posts/ 的返回結果,即全部文章列表。
但是,目前我們的 api 一股腦將全部文章列表的返回了。但是我們的部落格文章列表是有分頁功能的,接下來我們就使用 django-rest-framework 提供的分頁輔助類,一行程式碼就可以完成分頁功能。
---
![](https://img2018.cnblogs.com/blog/759200/202002/759200-20200213201956024-782757549.png)
**關注公眾號加入交流群**