• Django DRF 分页


    1. 分页器

    REST framework提供了分页的支持,内置的分页器需要继承 GenericAPIView 和 ListModelMixin,对查询所有接口进行分页。

    2. PageNumberPagination


    1. 可以自己继承 PageNumberPagination 设置属性,如下示例

    • 分页类
    from rest_framework.pagination import PageNumberPagination
    
    class CommonPageNumberPagination(PageNumberPagination):
        page_size = 3
        page_size_query_param = 'size'
        max_page_size = 5
        page_query_param = 'page'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    属性解释
    page_size每页数目
    page_query_param前端发送的页数关键字名,默认为”page”
    page_size_query_param前端发送的每页数目关键字名,默认为None
    max_page_size前端最多能设置的每页数量
    • 视图函数

    只要在视图函数中添加以下配置

    pagination_class = CommonPageNumberPagination
    
    • 1

    如果在视图内关闭分页功能,只需在视图内设置

    pagination_class = None
    
    • 1
    • 路由
    http://127.0.0.1:8000/students/?page=2&size=30		# 使用 GET 方法  
    
    • 1

    在路由中添加的 page 表示页码,size 表示一页展示的条数


    2. 也可以直接在 setting 配置文件中全局添加,如下所示

    • 配置文件
    REST_FRAMEWORK = {
        'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.PageNumberPagination',
        'PAGE_SIZE': 100  # 每页数目
    }
    
    • 1
    • 2
    • 3
    • 4

    3. LimitOffsetPagination

    1. 方法一,继承 LimitOffsetPagination 定义属性

    • 分页类
    class CommonLimitOffsetPagination(LimitOffsetPagination):
        default_limit = 2  
        limit_query_param = 'limit' 
        offset_query_param = 'offset'  
        max_limit = 5  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    属性解释
    default_limit默认展示条数,默认值与 PAGE_SIZE 设置一致
    limit_query_paramlimit 参数名,默认 ’limit’,控制取的条数
    offset_query_paramoffset 参数名,默认 ’offset’。控制从第 X 个位置偏移多少开始取数据
    max_limit最大limit限制,默认 None
    • 视图函数

    只要在视图函数中添加以下配置

    pagination_class = CommonLimitOffsetPagination
    
    • 1

    如果在视图内关闭分页功能,只需在视图内设置

    pagination_class = None
    
    • 1
    • 路由
    http://127.0.0.1:8000/students/?limit=2&offset=3		# 使用 GET 方法  
    
    • 1

    在路由中添加的 limit 表示一个页码展示的取出条数,offset 表示偏移数。例如上面的路由是每页展示 2 条数据,并且是从第 3 条数据开始展示 2 条,也就是展示的是 第 4、5 条数据。

    4. CursorPagination

    1. 方法一,继承 CursorPagination定义属性

    • 分页类
    class CommonCursorPagination(CursorPagination):
        cursor_query_param = 'cursor'  
        page_size = 3 
        ordering = 'id'  
    
    • 1
    • 2
    • 3
    • 4
    属性解释
    cursor_query_param默认查询字段,类似于 cursor = xxx,但是该值是随机的。
    page_size每页展示的数目
    ordering按什么排序,一般使用 id,需要注意其必须是表中有的字段
    • 视图函数

    只要在视图函数中添加以下配置

    pagination_class = CommonCursorPagination
    
    • 1

    如果在视图内关闭分页功能,只需在视图内设置

    pagination_class = None
    
    • 1

    5. 自定义基于 APIView 实现分页

    前面的使用内置分页的视图函数都需要继承 GenericAPIView、ListModelMixin,我们可以自己编写继承 APIView 的视图函数实现分页。

    • 视图函数(前提准备好内置的分页器)
    class MyPage(APIView):
        def get(self, request):
        	# 获取所有数据集
            books = models.Book.objects.all()
            
            # 对数据集进行分页,可以是自己配置了参数的分页器
            paginator = CommonPageNumberPagination()
            
            # 获取分页过后的数据
            qs = paginator.paginate_queryset(books, request, self)
            
            # 对数据进行序列化,多条数据需要添加 many=True
            res = serializer.BookSerializer(qs, many=True)
    
    		# 返回的方式一,只返回分页后的结果
            # return Response(res.data)
    
    		# 返回方式二,自己配置返回的其他信息,例如上一页下一页
            # return Response({
            #     'count': books.count(),
            #     'next': paginator.get_next_link(),
            #     'previous': paginator.get_previous_link(),
            #     'results': res.data
            # })
    
    		# 返回方式三,使用方法自动返回类似于方式二的内容
            return paginator.get_paginated_response(res.data)
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 路由
      和普通继承了 APIView 的视图函数一样配置路由。
      如果我们需要自动配置路由,我们可以先继承 ViewSet,有三种方式添加。
    1.	path('mypage/', BookViews.MyPage.as_view({'get': 'get'})),
    
    • 1
    2.	
    	from django.urls import path
    	from app01.view import BookViews
    	from rest_framework.routers import SimpleRouter
    	
    	router = SimpleRouter()
    	router.register('mypage', BookViews.MyPage, 'mypage')
    	
    	urlpatterns = []
    	urlpatterns += router.urls
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    3. 添加 @action(methods=['get',], detail=False)
    
    • 1

    这么编写的方式可以查看源码解析。

    源码解析

    • ListModelMixin 源码
    class ListModelMixin:
        """
        List a queryset.
        """
        def list(self, request, *args, **kwargs):
            queryset = self.filter_queryset(self.get_queryset())
    
            page = self.paginate_queryset(queryset)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return self.get_paginated_response(serializer.data)
    
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1. 查看 ListModelMixin 源码发现其调用了 self.paginate_queryset(queryset) 方法,而该方法并没有在拓展类中,而在 GenericAPIView 中会有该方法。

    • GenericAPIView 源码
    def paginate_queryset(self, queryset):
        if self.paginator is None:
            return None
        return self.paginator.paginate_queryset(queryset, self.request, view=self)
    
    • 1
    • 2
    • 3
    • 4
    1. 在 GenericAPIView 的 paginate_queryset 方法中的 paginator 调用了 paginate_queryset 方法。
    2. paginator 其实是一个方法当作属性调用,如下所示,其取了我们配置的分页器类
    @property
    def paginator(self):
        if not hasattr(self, '_paginator'):
            if self.pagination_class is None:
                self._paginator = None
            else:
                self._paginator = self.pagination_class()
        return self._paginator
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. paginate_queryset 方法也就是分页器类的方法,传入 queryset, self.request, view=self 参数,得到的结果就是分页过后的数据。
    2. 然后对数据进行序列化即可。除了序列化分页的结果,还可以配置例如数据集的长度等。其有一个方法配置了返回的样式,源码如下,我们仿照配置即可,或者直接调用该方法。
    def get_paginated_response(self, data):
        return Response(OrderedDict([
            ('count', self.page.paginator.count),
            ('next', self.get_next_link()),
            ('previous', self.get_previous_link()),
            ('results', data)
        ]))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    Yolov5的类激活图
    Promise的基本用法
    cocos----刚体
    SAP 异常现象之同一个IDoc可以被POST两次触发2张不同的物料凭证
    使用 VS 2022 开发C#项目的tips
    RabbitMQ学习记录
    【JUC】Java并发编程从挖坑到入土全解(2)
    java计算机毕业设计济南旅游网站MyBatis+系统+LW文档+源码+调试部署
    利用Spring Boot后端与Vue前端技术构建现代化电商平台
    柔顺机构学读书笔记1:悬臂梁变形
  • 原文地址:https://blog.csdn.net/m0_58987515/article/details/125430928