Pagination
為什么要分頁也不用多說了,大家都懂,DRF也自帶了分頁組件
這次用 前后端分離djangorestframework——序列化與反序列化數據 文章里用到的數據,數據庫用的mysql,因為django自帶的sqlite對於日期類型的數據會自動轉成時間戳,導致數據再序列化時無法正常序列化成日期類型而出錯
分頁組件還是跟前面的認證組件,權限組件,頻率組件很類似的
PageNumberPagination
在根目錄創建一個utils文件夾,在該文件夾里創建一個pagination文件,在其內定義一個分頁組件類,繼承自DRF里自帶的PageNumberPagination類:
DRF的分頁組件PageNumberPagination源碼
且注意這兩個方法,paginate_queryset和get_paginated_response,后面視圖類里會用到
讀django的源碼,可知我們可以自定義一些屬性或方法:
pagination:
url:
view:
訪問測試,顯示一共8個數據,有上一頁下一頁,當前顯示兩個數據,這是剛才自定義分頁組件時定義的
並且這個上一頁下一頁是可以直接點擊的
相關代碼:
pagination
from rest_framework.pagination import PageNumberPagination class MyPagination(PageNumberPagination): page_size = 2 page_size_query_param = 'size' max_page_size = 3
url:
from django.urls import path, re_path, include from demo1.views import BookView urlpatterns = [ path('book', BookView.as_view()), ]
view:
from demo1.serializers import BookSerializer from rest_framework.views import APIView from demo1.models import Book from utils.pagination import MyPagination class BookView(APIView): def get(self, request): queryset = Book.objects.all() # 1,實例化分頁器對象 page_obj = MyPagination() # 2,調用分頁方法去分頁queryset page_queryset = page_obj.paginate_queryset(queryset, request, view=self) # 3,把分頁好的數據序列化 ser_obj = BookSerializer(page_queryset, many=True) # 4, 帶着上一頁下一頁連接的響應 return page_obj.get_paginated_response(ser_obj.data)
serializer:
class BookSerializer(serializers.ModelSerializer): category_display = serializers.SerializerMethodField(read_only=True) authors = serializers.SerializerMethodField(read_only=True) publish_info = serializers.SerializerMethodField(read_only=True) def get_category_display(self, obj): return obj.get_category_display() def get_publish_info(self, obj): publish_obj = obj.publisher return {"id": publish_obj.id, 'title': publish_obj.title} def get_authors(self, obj): # obj是Book對象 author_list = obj.author.all() return [{"id": author_obj.id, "name": author_obj.name} for author_obj in author_list] class Meta: model = models.Book fields = '__all__' # depth = 1 # 表示外鍵查找層級 extra_kwargs = { "category": {"write_only": True}, "publisher": {"write_only": True}, "author": {"write_only": True}, }
LimitOffsetPagination
同樣的自定義分頁組件,並繼承此類即可:
pagination,其中的兩個屬性是看LimitOffsetPagination的源碼所得:
其他不用改,重啟項目訪問測試,一頁只有一個數據,有上一頁下一頁的鏈接
並且上一頁和下一頁可以直接點擊:
看起來好像和前面的PageNumberPagination差距不大對吧?LimitOffsetPagination,其參數offset是從第幾個開始向后找,limit是只一次顯示多少條數據的
當然你可以手動修改url的條件參數,從第一個開始找,每次顯示8,這樣就把我們本來就只有8個數據一起顯示了
說到這,順便說下,之前我們研究的Python爬蟲, 有時候在爬數據時是發現網頁沒有刷新,但是是ajax異步請求,每次請求只顯示一定數量的,就是因為有這個limit參數在,當時我們是怎么解決呢?就是直接在url后面修改limit參數,一次請求幾百條數據或者多少都行,這樣我們只請求了一次,但是這一下就拿到了多條數據,前面我們用的頻率組件可以限制次數,到這我們一次請求拿幾百或者幾千這種的,就不好判斷了
相關代碼:
pagination:
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination class MyPagination(LimitOffsetPagination): default_limit = 1 max_limit = 3
view和url,serializers其實都沒做任何更改:

from demo1.serializers import BookSerializer from rest_framework.views import APIView from demo1.models import Book from utils.pagination import MyPagination class BookView(APIView): def get(self, request): queryset = Book.objects.all() # 1,實例化分頁器對象 page_obj = MyPagination() # 2,調用分頁方法去分頁queryset page_queryset = page_obj.paginate_queryset(queryset, request, view=self) # 3,把分頁好的數據序列化 ser_obj = BookSerializer(page_queryset, many=True) # 4, 帶着上一頁下一頁連接的響應 return page_obj.get_paginated_response(ser_obj.data)

from django.urls import path, re_path, include from demo1.views import BookView urlpatterns = [ path('book', BookView.as_view()), ]

from rest_framework import serializers from demo1 import models class PublishSerializer(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField(max_length=32) class AuthorSerializer(serializers.Serializer): id = serializers.IntegerField() name = serializers.CharField(max_length=32) class BookSerializer(serializers.ModelSerializer): category_display = serializers.SerializerMethodField(read_only=True) authors = serializers.SerializerMethodField(read_only=True) publish_info = serializers.SerializerMethodField(read_only=True) def get_category_display(self, obj): return obj.get_category_display() def get_publish_info(self, obj): publish_obj = obj.publisher return {"id": publish_obj.id, 'title': publish_obj.title} def get_authors(self, obj): # obj是Book對象 author_list = obj.author.all() return [{"id": author_obj.id, "name": author_obj.name} for author_obj in author_list] class Meta: model = models.Book fields = '__all__' # depth = 1 # 表示外鍵查找層級 extra_kwargs = { "category": {"write_only": True}, "publisher": {"write_only": True}, "author": {"write_only": True}, }
CursorPagination
這個游標分頁,可以對訪問的url的條件參數隱藏,防止被人根據url的條件參數猜出我們的數據量,可能有潛在的隱患
pagination:
訪問測試,按id為11(11為數據庫里的最后一個數據)開始倒序排序
打開數據庫,確實是倒序的
再點擊上一頁下一頁,發現其參數是加密了的,根本無法通過這個條件參數猜解出我們的數據量
相關代碼:

from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination class MyPagination(CursorPagination): page_size = 2 ordering = '-id' # 表示從哪個字段開始排序
其他沒有做任何更改,不再貼出浪費篇幅了
當然,這個還是可以使用之前的Modelserializer來優化代碼,
# coding:utf-8 from rest_framework.generics import GenericAPIView from rest_framework.mixins import ListModelMixin from demo1.serializers import BookSerializer from demo1.models import Book from utils.pagination import MyPagination class BookView(GenericAPIView,ListModelMixin): queryset = Book.objects.all() serializer_class = BookSerializer pagination_class = MyPagination def get(self, request): return self.list(request)
其他不用作任何更改,訪問測試:
為什么這么方便,因為ListModelMixin中做了處理,假如有分頁組件,那么就獲取了分頁的參數再返回:
總結:
多看源碼,根據需求選用源碼的分頁組件類,設定相關的參數