1. 程式人生 > >第 9 篇:實現分類、標籤、歸檔日期介面

第 9 篇:實現分類、標籤、歸檔日期介面

![](https://img2020.cnblogs.com/blog/759200/202004/759200-20200415161158343-1662112908.jpg) 作者:[HelloGitHub-追夢人物](https://www.zmrenwu.com) 我們的部落格有一個側邊欄功能,分別列出部落格文章的分類列表、標籤列表、歸檔時間列表,通過點選側邊欄對應的條目,還可以進入相應的頁面。例如點選某個分類,部落格將跳轉到該分類下全部文章列表頁面。這些資料的展示都需要開發對應的介面,以便前端呼叫獲取資料。 分類列表、標籤列表實現比較簡單,我們這裡給出介面的設計規範,大家可以使用前幾篇教程中學到的知識點輕鬆實現(具體實現可參考 [GtiHub 上的原始碼](https://github.com/HelloGitHub-Team/HelloDjango-REST-framework-tutorial))。 分類列表介面: /categories/ 標籤列表介面:/tags/ 歸檔日期列表的介面實現稍微複雜一點,因為我們需要從已有文章中歸納文章發表日期。事實上,我們在上一部教程 HelloDjango - Django部落格教程(第二版)的 [頁面側邊欄:使用自定義模板標籤](https://www.zmrenwu.com/courses/hellodjango-blog-tutorial/materials/70/) 已經講解了如何獲取歸檔日期列表,只是當時返回的歸檔日期列表直接用於模板的渲染,而這裡我們需要將歸檔日期列表序列化後通過 API 介面返回。 具體來說,獲取部落格文章發表時間歸檔列表的方法是呼叫查詢集(QuerySet)的 `dates` 方法,提取記錄中的日期。核心程式碼就一句: ```python Post.objects.dates('created_time', 'month', order='DESC') ``` 這裡 `Post.objects.dates` 方法會返回一個列表,列表中的元素為每一篇文章(Post)的建立日期(已去重),日期都是 Python 的 `date` 物件,精確到月份,降序排列。 有了返回的歸檔日期列表,接下來就實現相應的 API 介面檢視函式: ```python blog/views.py from rest_framework import mixins, status, viewsets from rest_framework.decorators import action from rest_framework.serializers import DateField class PostViewSet( mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet ): # ... @action( methods=["GET"], detail=False, url_path="archive/dates", url_name="archive-date" ) def list_archive_dates(self, request, *args, **kwargs): dates = Post.objects.dates("created_time", "month", order="DESC") date_field = DateField() data = [date_field.to_representation(date) for date in dates] return Response(data=data, status=status.HTTP_200_OK) ``` 注意這裡我們涉及到了幾個以前沒有詳細講解過的用法。 一是 `action` 裝飾器,它用來裝飾一個檢視集中的方法,被裝飾的方法會被 django-rest-framework 的路由自動註冊為一個 API 介面。 回顧一下我們之前在使用檢視集 viewset 時提到過 action(動作)的概念,django-rest-framework 預定義了幾個標準的動作,分別為 list 獲取資源列表,retrieve 獲取單個資源、update 和 partial_update 更新資源、destroy 刪除資源,這些 action 具體的實現方法,分別由 mixins 模組中的混入類提供。例如 [用類檢視實現首頁 API](https://www.zmrenwu.com/courses/django-rest-framework-tutorial/materials/94/) 中我們介紹過 `mixins.ListModelMixin`,這個混入類提供了 list 動作對應的標準實現,即 list 方法。檢視集中所有以上提及的以標準動作命名的方法,都會被 django-rest-framework 的路由自動註冊為標準的 API 介面。 django-rest-framework 預設只能識別標準命名的檢視集方法並將其註冊為 API,但我們可以新增更多非標準的 action,而為了讓 django-rest-framework 能夠識別這些方法,就需要使用 `action` 裝飾器進行裝飾。 其實我們可以簡單地將 action 裝飾的方法看作是一個檢視函式的實現,因此可以看到方法傳入的第一個引數為 request 請求物件,函式體就是這個檢視函式需要執行的邏輯,顯然,方法最終必須要返回一個 HTTP 響應物件。 action 裝飾器通常用於在檢視集中新增額外的介面實現。例如這裡我們已有了 `PostViewSet` 檢視集,標準的 list 實現了獲取文章資源列表的邏輯。我們想新增一個獲取文章歸檔日期列表的介面,因此添加了一個 `list_archive_dates` 方法,並使用 action 進行裝飾。通常如果要在檢視集中新增額外的介面實現,可以使用如下的模板程式碼: ```python @action( methods=["allowed http method name"], detail=False or True, url_path="url/path", url_name="url name" ) def method_name(self, request, *args, **kwargs): # 介面邏輯的具體實現,返回一個 Response ``` 通常 action 裝飾器以下 4 個引數都會設定: methods:一個列表,指定訪問這個介面時允許的 HTTP 方法(GET、POST、PUT、PATCH、DELETE) detail:True 或者 False。設定為 True,自動註冊的介面 URL 中會新增一個 pk 路徑引數(請看下面的示例),否則不會。 url_path:自動註冊的介面 URL。 url_name:介面名,主要用於通過介面名字反解對應的 URL。 當然,我們還可以在 action 中設定所有 `ViewSet` 類所支援的類屬性,例如 `serializer_class`、`pagination_class`、`permission_classes` 等,用於覆蓋類檢視中設定的屬性值。 以上是 action 用法的一個基本介紹,現在來分析一下 `list_archive_dates` 這個 action 來加深理解。 `methods` 引數指定介面需要通過 GET 方法訪問,detail 為 `False`,`url_path` 設定為 archive/dates,因此最終自動生成的介面路由就是 /posts/archive/dates/。如果我們設定 detail 為 True,那麼生成的介面路由就是