Django REST framework API 指南(17):分頁

官方原文連接
本系列文章 github 地址
轉載請註明出處html

分頁

REST framework 包含對可定製分頁樣式的支持。這使你能夠將較大的結果集分紅單獨的數據頁面。python

分頁 API 支持:git

  • 以分頁連接的形式做爲響應內容的一部分。
  • 以分頁連接的形式包含在響應的 header 中,如 Content-RangeLink.

內置的樣式目前是以分頁連接的形式做爲響應內容的一部分。使用可瀏覽的 API 時,此樣式更易於訪問。github

分頁僅在你使用通用視圖或視圖集時自動執行。若是你使用的是常規 APIView,則須要本身調用分頁 API 以確保返回分頁響應。示例請參閱 mixins.ListModelMixingenerics.GenericAPIView 類的源代碼。數據庫

能夠經過將分頁類設置爲 None,關閉分頁。django

設置分頁樣式

分頁樣式可使用 DEFAULT_PAGINATION_CLASSPAGE_SIZE setting key 全局設置。例如,要使用內置的 limit/offset 分頁,你能夠這樣作:api

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 100
}
複製代碼

請注意,你須要設置分頁類和應使用的頁面大小。默認狀況下,DEFAULT_PAGINATION_CLASSPAGE_SIZE 都是 Nonebash

你還可使用 pagination_class 屬性在單個視圖上設置分頁類。一般,你但願在整個 API 中使用相同的分頁樣式,但你可能但願在每一個視圖的基礎上更改分頁的各個方面,例如默認或最大頁面大小。app

修改分頁樣式

若是要修改分頁樣式的特定方面,則須要繼承其中一個分頁類,並設置要更改的屬性。ide

class LargeResultsSetPagination(PageNumberPagination):
    page_size = 1000
    page_size_query_param = 'page_size'
    max_page_size = 10000

class StandardResultsSetPagination(PageNumberPagination):
    page_size = 100
    page_size_query_param = 'page_size'
    max_page_size = 1000
複製代碼

而後,你可使用 .pagination_class 屬性將新樣式應用於視圖:

class BillingRecordsView(generics.ListAPIView):
    queryset = Billing.objects.all()
    serializer_class = BillingRecordsSerializer
    pagination_class = LargeResultsSetPagination
複製代碼

或者使用 DEFAULT_PAGINATION_CLASS setting key 全局應用樣式。例如:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
}
複製代碼

API 參考

PageNumberPagination

此分頁樣式在請求查詢參數中接受一個頁碼值。

Request:

GET https://api.example.org/accounts/?page=4
複製代碼

Response:

HTTP 200 OK
{
    "count": 1023
    "next": "https://api.example.org/accounts/?page=5",
    "previous": "https://api.example.org/accounts/?page=3",
    "results": [
       …
    ]
}
複製代碼

Setup

要全局啓用 PageNumberPagination 樣式,請使用如下配置,並根據須要設置 PAGE_SIZE

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 100
}
複製代碼

若是使用的是 GenericAPIView 的子類,還能夠設置 pagination_class 屬性以在每一個視圖的基礎上選擇 PageNumberPagination

Configuration

PageNumberPagination 類包含一些能夠被覆蓋以修改分頁樣式的屬性。

要設置這些屬性,你應該繼承 PageNumberPagination 類,而後像上面那樣啓用你的自定義分頁類。

  • django_paginator_class - 要使用的 Django Paginator 類。默認是 django.core.paginator.Paginator,對於大多數用例來講應該沒問題。
  • page_size - 指定頁面大小的數字值。若是設置,則會覆蓋 PAGE_SIZE setting。默認值與 PAGE_SIZE setting key 相同。
  • page_query_param - 一個字符串值,指定用於分頁控件的查詢參數的名稱。
  • page_size_query_param - 一個字符串值,指定查詢參數的名稱,容許客戶端根據每一個請求設置頁面大小。默認爲 None,表示客戶端可能沒法控制所請求的頁面大小。
  • max_page_size - 一個數字值,表示容許的最大頁面大小。該屬性僅在 page_size_query_param 也被設置時有效。
  • last_page_strings - 字符串列表或元組,用於指定可能與 page_query_param 一塊兒使用的值,用以請求集合中的最終頁面。默認爲 ('last',)
  • template - 在可瀏覽 API 中渲染分頁控件時使用的模板的名稱。可能會被覆蓋以修改渲染樣式,或設置爲 None 以徹底禁用 HTML 分頁控件。默認爲 "rest_framework/pagination/numbers.html"

LimitOffsetPagination

這種分頁樣式反映了查找多個數據庫記錄時使用的語法。客戶端包含 「limit」 和 「offset」 查詢參數。limit 表示要返回的 item 的最大數量,而且等同於其餘樣式中的 page_size。offset 指定查詢的起始位置與完整的未分類 item 集的關係。

Request:

GET https://api.example.org/accounts/?limit=100&offset=400
複製代碼

Response:

HTTP 200 OK
{
    "count": 1023
    "next": "https://api.example.org/accounts/?limit=100&offset=500",
    "previous": "https://api.example.org/accounts/?limit=100&offset=300",
    "results": [
       …
    ]
}
複製代碼

Setup

要全局啓用 LimitOffsetPagination 樣式,請使用如下配置:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'
}
複製代碼

或者,你也能夠設置一個 PAGE_SIZE 鍵。若是使用了 PAGE_SIZE 參數,則 limit 查詢參數將是可選的,而且可能會被客戶端忽略。

若是使用的是 GenericAPIView 子類,還能夠設置 pagination_class 屬性以基於每一個視圖選擇 LimitOffsetPagination

Configuration

LimitOffsetPagination 類包含一些能夠被覆蓋以修改分頁樣式的屬性。

要設置這些屬性,應該繼承 LimitOffsetPagination 類,而後像上面那樣啓用你的自定義分頁類。

  • default_limit - 一個數字值,指定客戶端在查詢參數中未提供的 limit 。默認值與 PAGE_SIZE setting key 相同。
  • limit_query_param - 一個字符串值,指示 「limit」 查詢參數的名稱。默認爲 'limit'
  • offset_query_param - 一個字符串值,指示 「offset」 查詢參數的名稱。默認爲 'offset'
  • max_limit - 一個數字值,表示客戶端能夠要求的最大容許 limit。默認爲 None
  • template - 在可瀏覽 API 中渲染分頁控件時使用的模板的名稱。可能會被覆蓋以修改渲染樣式,或設置爲 None 以徹底禁用 HTML 分頁控件。默認爲 "rest_framework/pagination/numbers.html"

CursorPagination

基於遊標的分頁提供了一個不透明的 「遊標」 指示器,客戶端可使用該指示器來翻閱結果集。此分頁樣式僅提供前向和反向控件,而且不容許客戶端導航到任意位置。

基於遊標的分頁須要在結果集中存在惟一的,不變的 item 順序。這種排序一般能夠是記錄上的建立時間戳,由於這確保了排序的一致性。

基於遊標的分頁比其餘方案更復雜。它還要求結果集渲染固定順序,而且不容許客戶端任意索引結果集。但它確實提供瞭如下好處:

  • 提供一致的分頁視圖。正確使用時 CursorPagination 確保客戶端在分頁時不會看到同一個 item,即便在分頁過程當中其餘客戶端正在插入新 item。
  • 支持使用很是大的數據集。使用極大數據集分頁時,使用基於偏移量的分頁樣式可能會變得效率低下或沒法使用。基於遊標的分頁方案具備固定時間屬性,而且不會隨着數據集大小的增長而減慢。

細節和限制

正確使用基於遊標的分頁須要稍微注意細節。你須要考慮但願將該方案應用於何種順序。默認是按 "-created" 排序。這假設在模型實例上必須有一個 「created」 時間戳字段,而且會渲染一個 「時間軸」 樣式分頁視圖,其中最近添加的 item 是第一個。

你能夠經過重寫分頁類上的 'ordering' 屬性或者將 OrderingFilter 過濾器類與 CursorPagination 一塊兒使用來修改排序。與 OrderingFilter 一塊兒使用時,你應該考慮限制用戶能夠排序的字段。

正確使用遊標分頁應該有一個知足如下條件的排序字段:

  • 在建立時應該是一個不變的值,例如時間戳,slug,或其餘只設置一次的字段。
  • 應該是獨特的,或幾乎獨一無二的。毫秒精度時間戳就是一個很好的例子。這種遊標分頁的實現使用了一種智能的 「位置 + 偏移」 風格,容許它正確地支持非嚴格惟一的值做爲排序。
  • 應該是能夠強制爲字符串的非空值。
  • 不該該是一個 float。精度錯誤很容易致使錯誤的結果。提示:改用小數。(若是你已經有一個 float 字段而且必須對其進行分頁,則能夠在此處找到使用小數來限定精度的示例。)
  • 該字段應該有一個數據庫索引。

使用不知足這些約束條件的排序字段一般仍然有效,可是你將失去遊標分頁的一些好處。

Setup

要全局啓用 CursorPagination 樣式,請使用如下配置,根據須要修改 PAGE_SIZE

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination',
    'PAGE_SIZE': 100
}
複製代碼

若是使用的是 GenericAPIView 子類,還能夠設置 pagination_class 屬性以基於每一個視圖選擇 CursorPagination

Configuration

CursorPagination 類包含一些能夠被覆蓋以修改分頁樣式的屬性。

要設置這些屬性,你應該繼承 CursorPagination 類,而後像上面那樣啓用你的自定義分頁類。

  • page_size = 指定頁面大小的數字值。若是設置,則會覆蓋 PAGE_SIZE 設置。默認值與 PAGE_SIZE setting key 相同。
  • cursor_query_param = 一個字符串值,指定 「遊標」 查詢參數的名稱。默認爲 'cursor'.
  • ordering = 這應該是一個字符串或字符串列表,指定將應用基於遊標的分頁的字段。例如: ordering = 'slug'。默認爲 -created。該值也能夠經過在視圖上使用 OrderingFilter 來覆蓋。
  • template = 在可瀏覽 API 中渲染分頁控件時使用的模板的名稱。可能會被覆蓋以修改渲染樣式,或設置爲 None 以徹底禁用 HTML 分頁控件。默認爲 "rest_framework/pagination/previous_and_next.html"

自定義分頁樣式

要建立自定義分頁序列化類,你應該繼承 pagination.BasePagination 並覆蓋 paginate_queryset(self, queryset, request, view=None)get_paginated_response(self, data) 方法:

  • paginate_queryset 方法被傳遞給初始查詢集,而且應該返回一個只包含請求頁面中的數據的可迭代對象。
  • get_paginated_response 方法傳遞序列化的頁面數據,並返回一個 Response 實例。

請注意,paginate_queryset 方法能夠在分頁實例上設置狀態,然後 get_paginated_response 方法可使用它。

舉個栗子

假設咱們想用一個修改後的格式替換默認的分頁輸出樣式,該樣式包含嵌套的 「links」 key(包含上一頁,下一頁連接)。咱們能夠像這樣指定一個自定義分頁類:

class CustomPagination(pagination.PageNumberPagination):
    def get_paginated_response(self, data):
        return Response({
            'links': {
                'next': self.get_next_link(),
                'previous': self.get_previous_link()
            },
            'count': self.page.paginator.count,
            'results': data
        })
複製代碼

而後咱們須要在配置中設置自定義類:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPagination',
    'PAGE_SIZE': 100
}
複製代碼

請注意,若是你關心如何在可瀏覽的 API 中顯示鍵的順序,則能夠在構建分頁響應的主體時選擇使用 OrderedDict,這是可選的。

使用你的自定義分頁類

要默認使用你的自定義分頁類,請使用 DEFAULT_PAGINATION_CLASS setting:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination',
    'PAGE_SIZE': 100
}
複製代碼

列表端點的 API 響應如今將包含一個 Link header,而不是將分頁連接包含爲響應主體的一部分。

分頁和模式

經過實現 get_schema_fields() 方法,你還可使分頁控件可用於 REST framework 提供的模式自動生成。此方法應具備如下簽名:

get_schema_fields(self, view)

該方法應該返回一個 coreapi.Field 實例列表。


Link Header

自定義分頁樣式,使用 'Link' header


HTML 分頁控件

默認狀況下,使用分頁類將致使 HTML 分頁控件顯示在可瀏覽的 API 中。有兩種內置顯示樣式。 PageNumberPaginationLimitOffsetPagination 類顯示包含上一頁和下一頁控件的頁碼列表。 CursorPagination 類顯示更簡單的樣式,只顯示上一頁和下一頁控件。

自定義控件

你能夠覆蓋渲染 HTML 分頁控件的模板。這兩種內置式樣是:

  • rest_framework/pagination/numbers.html
  • rest_framework/pagination/previous_and_next.html

在全局模板目錄中提供具備這些路徑的模板將覆蓋相關分頁類的默認渲染。

或者,你能夠經過在現有類的子類上徹底禁用 HTML 分頁控件,將 template=None 設置爲該類的屬性。而後,你須要配置你的 DEFAULT_PAGINATION_CLASS setting key,以將你的自定義類用做默認分頁樣式。

低級 API

用於肯定分頁類是否應顯示控件的低級 API 做爲分頁實例上的 display_page_controls 屬性公開。若是須要顯示HTML 分頁控件,自定義分頁類應該在 paginate_queryset 方法中設置爲 True

.to_html().get_html_context() 方法也能夠在自定義分頁類中重寫,以便進一步自定義控件的渲染方式。

相關文章
相關標籤/搜索