Django REST Framework 分頁(Pagination)詳解
在前面的DRF系列教程中,我們以博客為例介紹了序列化器, 使用基于類的視圖APIView和ModelViewSet開發了針對文章資源進行增刪查改的完整API端點,并詳細對權限和認證(含jwt認證)進行了總結與演示。在本篇文章中我們將向你演示如何在Django REST Framework中使用分頁。
分頁
為什么要分頁? 當你的數據庫數據量非常大時,如果一次將這些數據查詢出來, 必然加大了服務器內存的負載,降低了系統的運行速度。一種更好的方式是將數據分段展示給用戶。如果用戶在展示的分段數據中沒有找到自己的內容,可以通過指定頁碼或翻頁的方式查看更多數據,直到找到自己想要的內容為止。
Django REST Framework提供3種分頁類,接下來我們會分別進行演示。
PageNumberPagination類:簡單分頁器。支持用戶按?page=3這種方式查詢,你可以通過page_size這個參數手動指定每頁展示給用戶數據的數量。它還支持用戶按?page=3&size=10這種更靈活的方式進行查詢,這樣用戶不僅可以選擇頁碼,還可以選擇每頁展示數據的數量。對于第二種情況,你通常還需要設置max_page_size這個參數限制每頁展示數據的最大數量,以防止用戶進行惡意查詢(比如size=10000), 這樣一頁展示1萬條數據將使分頁變得沒有意義。 LimitOffsetPagination類:偏移分頁器。支持用戶按?limit=20&offset=100這種方式進行查詢。offset是查詢數據的起始點,limit是每頁展示數據的最大條數,類似于page_size。當你使用這個類時,你通常還需要設置max_limit這個參數來限制展示給用戶數據的最大數量。 CursorPagination類:加密分頁器。這是DRF提供的加密分頁查詢,僅支持用戶按響應提供的上一頁和下一頁鏈接進行分頁查詢,每頁的頁碼都是加密的。使用這種方式進行分頁需要你的模型有'created'這個字段,否則你要手動指定ordering排序才能進行使用。使用PageNumberPagination類
DRF中使用默認分頁類的最簡單方式就是在settings.py中進行全局配置,如下所示:
REST_FRAMEWORK ={ ’DEFAULT_PAGINATION_CLASS’:’rest_framework.pagination.PageNumberPagination’,’PAGE_SIZE’:2}
展示效果如下,每頁展示兩條記錄, 不支持用戶指定每頁展示數據的數量。
但是如果你希望用戶按?page=3&size=10這種更靈活的方式進行查詢,你就要進行個性化定制。在實際開發過程中,定制比使用默認的分頁類更常見,具體做法如下。
第一步: 在app目錄下新建pagination.py, 添加如下代碼:
#blog/pagination.py
from rest_framework.pagination import PageNumberPagination class MyPageNumberPagination(PageNumberPagination): page_size = 2 # default page size page_size_query_param = ’size’ # ?page=xx&size=?? max_page_size = 10 # max page size
我們自定義了一個MyPageNumberPagination類,該類繼承了PageNumberPagination類。我們通過page_size設置了每頁默認展示數據的條數,通過page_size_query_param設置了每頁size的參數名以及通過max_page_size設置了每個可以展示的最大數據條數。
第二步:使用自定義的分頁類
在基于類的視圖中,你可以使用pagination_class這個屬性使用自定義的分頁類,如下所示:
from rest_framework import viewsetsfrom .pagination import MyPageNumberPagination class ArticleViewSet(viewsets.ModelViewSet): # 用一個視圖集替代ArticleList和ArticleDetail兩個視圖 queryset = Article.objects.all() serializer_class = ArticleSerializer pagination_class = MyPageNumberPagination # 自行添加,將request.user與author綁定 def perform_create(self, serializer): serializer.save(author=self.request.user) # 自行添加,將request.user與author綁定 def perform_update(self, serializer): serializer.save(author=self.request.user)
展示效果如下所示:
當然定制分頁類不限于指定page_size和max_page_size這些屬性,你還可以改變響應數據的輸出格式。比如我們這里希望把next和previous放在一個名為links的key里,我們可以修改MyPageNumberPagination類,重寫get_paginated_response方法:
from rest_framework.pagination import PageNumberPaginationfrom rest_framework.response import Response class MyPageNumberPagination(PageNumberPagination): page_size = 2 # default page size page_size_query_param = ’size’ # ?page=xx&size=?? max_page_size = 10 # max page size 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 })
新的展示效果如下所示:
注意:重寫get_paginated_response方法非常有用,你還可以給分頁響應數據傳遞額外的內容,比如code狀態碼等等。
前面的例子中我們只在單個基于類的視圖或視圖集中使用到了分頁類,你還可以修改settings.py全局使用你自定義的分頁類,如下所示。展示效果是一樣的,我們就不詳細演示了。
REST_FRAMEWORK = { ’DEFAULT_PAGINATION_CLASS’: ’blog.pagination.MyPageNumberPagination’,}
使用LimitOffsetPagination類
使用這個分頁類最簡單的方式就是在settings.py中進行全局配置,如下所示:
REST_FRAMEWORK = { ’DEFAULT_PAGINATION_CLASS’: ’rest_framework.pagination.LimitOffsetPagination’}
展示效果如下所示,從第6條數據查起,每頁展示2條。
你也可以自定義MyLimitOffsetPagination類,在單個視圖或視圖集中使用,或者全局使用。
from rest_framework.pagination import LimitOffsetPagination class MyLimitOffsetPagination(LimitOffsetPagination): default_limit = 5 # default limit per age limit_query_param = ’limit’ # default is limit offset_query_param = ’offset’ # default param is offset max_limit = 10 # max limit per age
使用CursorPagination類
全局使用
REST_FRAMEWORK = { ’DEFAULT_PAGINATION_CLASS’: ’rest_framework.pagination.CursorPagination’, ’PAGE_SIZE’: 2}
展示效果如下所示:
什么? 為什么會出錯誤? 使用CursorPagination類需要你的模型里有created這個字段,否則你需要手動指定ordering字段。這是因為CursorPagination類只能對排過序的查詢集進行分頁展示。我們的Article模型只有create_date字段,沒有created這個字段,所以會報錯。
為了解決這個問題,我們需要自定義一個MyCursorPagination類,手動指定按create_date排序, 如下所示:
#blog/pagination.py
from rest_framework.pagination import CursorPagination class MyArticleCursorPagination(CursorPagination): page_size = 3 # Default number of records per age page_size_query_param = ’page_size’ cursor_query_param = ’cursor’ # Default is cursor ordering = ’-create_date’
修改settings.py, 使用自己定義的分頁類。
REST_FRAMEWORK = { ’DEFAULT_PAGINATION_CLASS’: ’blog.pagination.MyArticleCursorPagination’,}
響應效果如下所示,你將得到previous和next分頁鏈接。頁碼都加密了, 鏈接里不再顯示頁碼號碼。默認每頁展示3條記錄, 如果使用?page_size=2進行查詢,每頁你將得到兩條記錄。
當然由于這個ordering字段與模型相關,我們并不推薦全局使用自定義的CursorPagination類,更好的方式是在GenericsAPIView或視圖集viewsets中通過pagination_class屬性指定,如下所示:
from rest_framework import viewsetsfrom .pagination import MyArticleCursorPagination class ArticleViewSet(viewsets.ModelViewSet): # 用一個視圖集替代ArticleList和ArticleDetail兩個視圖 queryset = Article.objects.all() serializer_class = ArticleSerializer pagination_class = MyArticleCursorPagination # 自行添加,將request.user與author綁定 def perform_create(self, serializer): serializer.save(author=self.request.user) # 自行添加,將request.user與author綁定 def perform_update(self, serializer): serializer.save(author=self.request.user)
函數類視圖中使用分頁類
注意pagination_class屬性僅支持在genericsAPIView和視圖集viewset中配置使用。如果你使用函數或簡單的APIView開發API視圖,那么你需要對你的數據進行手動分頁,一個具體使用例子如下所示:
from rest_framework.pagination import PageNumberPaginationclass ArticleList0(APIView): ''' List all articles, or create a new article. ''' def get(self, request, format=None): articles = Article.objects.all() page = PageNumberPagination() # 產生一個分頁器對象 page.page_size = 3 # 默認每頁顯示的多少條記錄 page.page_query_param = ’page’ # 默認查詢參數名為 page page.page_size_query_param = ’size’ # 前臺控制每頁顯示的最大條數 page.max_page_size = 10 # 后臺控制顯示的最大記錄條數,防止用戶輸入的查詢條數過大 ret = page.paginate_queryset(articles, request) serializer = ArticleSerializer(ret, many=True) return Response(serializer.data)
小結
本文總結了DRF提供的3種分頁類并詳細演示了如何使用它們,你學會了嗎?
到此這篇關于Django REST Framework 分頁(Pagination)詳解的文章就介紹到這了,更多相關Django REST Framework 分頁內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!
相關文章:
