前后端分離djangorestframework——分頁組件


 

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)
View
from django.urls import path, re_path, include
from demo1.views import BookView

urlpatterns = [
    path('book', BookView.as_view()),
]
url
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},
        }
serializers

 

CursorPagination

這個游標分頁,可以對訪問的url的條件參數隱藏,防止被人根據url的條件參數猜出我們的數據量,可能有潛在的隱患

 

pagination:

 

訪問測試,按id為11(11為數據庫里的最后一個數據)開始倒序排序

 打開數據庫,確實是倒序的

 

再點擊上一頁下一頁,發現其參數是加密了的,根本無法通過這個條件參數猜解出我們的數據量

 

 

 

 相關代碼:

from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination


class MyPagination(CursorPagination):
    page_size = 2
    ordering = '-id'  # 表示從哪個字段開始排序
pagination

其他沒有做任何更改,不再貼出浪費篇幅了

 

當然,這個還是可以使用之前的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中做了處理,假如有分頁組件,那么就獲取了分頁的參數再返回:

 

 

總結:

 多看源碼,根據需求選用源碼的分頁組件類,設定相關的參數

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM