• DjangoRestFramework框架三种分页功能的实现 - 在DjangoStarter项目模板中封装


    前言

    继续Django后端开发系列文章。刚好遇到一个分页的需求,就记录一下。

    Django作为一个“全家桶”型的框架,本身啥都有,分页组件也是有的,但默认的分页组件没有对API开发做优化,所以DjangoRestFramework这个专门写API的框架又把Django的分页组件包装了一层,集成在viewsets里的时候会更方便。

    不过我们不可能一直用viewsets,有一部分API还是要用自由度更高的ApiView的,但ApiView里又没办法直接使用默认的分页组件,这时我们就需要封装一下。

    并且DjangoRestFramework默认的分页信息也不够全,比如没有总页数,这点我们也可以在封装的时候魔改一下。

    DRF中的分页方式

    DRF中为我们封装了三种分页方式,分别是:

    • PageNumberPagination:顾名思义,不解释
    • LimitOffsetPagination:Offset分页
    • CursorPagination:加密分页

    本文打算只介绍最常用的第一种,后面两种同时也会做封装,但篇幅关系就不介绍了,有兴趣的同学可以尝试使用一下。

    开始代码

    首先还是在我们的「DjangoStarter」项目中,在utils目录下新建一个名为paginator的Python Package。

    因为代码不多,我们直接写在utils/paginator/__init__.py文件下就好。

    from collections import OrderedDict
    
    from django.core.paginator import Paginator
    from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
    from rest_framework.response import Response
    
    
    class NumberPaginator(PageNumberPagination):
        """页码分页"""
        def __init__(
                self,
                page_size,
                page_size_query_param='page_size',
                page_query_param='page',
                max_page_size=None
        ):
            """
            初始化分页
    
            :param page_size: 每页显示多少条
            :param page_size_query_param: URL中每页显示条数的参数
            :param page_query_param: URL中页码的参数
            :param max_page_size: 最大页码数限制
            """
            self.page_size = page_size
            self.page_size_query_param = page_size_query_param
            self.page_query_param = page_query_param
            self.max_page_size = max_page_size
    
        def get_paginated_response(self, data):
            paginator: Paginator = self.page.paginator
    
            return Response(OrderedDict([
                ('total_item_count', paginator.count),
                ('page_count', paginator.num_pages),
                ('page_number', self.page.number),
                ('page_size', self.page_size),
                ('next', self.get_next_link()),
                ('previous', self.get_previous_link()),
                ('results', data)
            ]))
    
    
    class LimitOffsetPaginator(LimitOffsetPagination):
        """Offset分页"""
        default_limit = 1
        limit_query_param = 'limit'
        offset_query_param = 'offset'
        max_limit = 999
    
    
    class CursorPaginator(CursorPagination):
        """加密分页"""
        cursor_query_param = 'cursor'
        page_size = 1
        ordering = '-id'  # 重写要排序的字段
    

    针对前面说的“DjangoRestFramework默认的分页信息也不够全”问题,我重写了get_paginated_response方法,在返回值中加入这几个参数

    • page_count:总页数
    • page_number:当前页码
    • page_size:每页数量

    然后另外两个参数也改了名字,更直观,更符合我们平时的开发习惯。

    ...

    这样就完成了封装,我们接下来在代码里测试一下

    测试接口

    来写个测试接口看看效果

    from utils.paginator import NumberPaginator
    
    @swagger_auto_schema(
        method='get', operation_summary='测试分页功能',
        manual_parameters=[
            openapi.Parameter('page', openapi.IN_QUERY, type=openapi.TYPE_NUMBER),
            openapi.Parameter('page_size', openapi.IN_QUERY, type=openapi.TYPE_NUMBER),
        ])
    @api_view()
    def test_page(request):
        # 测试数据
        data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        paginator = NumberPaginator(request.query_params.get('page_size', 10))
        return paginator.get_paginated_response({
            'data': paginator.paginate_queryset(queryset=data, request=request)
        })
    

    配置一下路由

    urlpatterns = [
        path('test_page', views.test_page),
    ]
    

    测试效果

    写完的接口接受两个参数,pagepage_size,我在@swagger_auto_schema装饰器里声明了这两个参数,方便我们在Swagger文档中做测试。

    我们设定page_size=5,拿到的JSON数据是这样的:

    {
      "message": "请求成功",
      "code": 200,
      "data": {
        "total_item_count": 10,
        "page_count": 2,
        "page_number": 1,
        "page_size": "5",
        "next": "http://127.0.0.1:8005/core/test_page?page=2&page_size=5",
        "previous": null,
        "results": {
          "data": [
            1,
            2,
            3,
            4,
            5
          ]
        }
      }
    }
    

    效果不错,很清晰。

    收工。

    参考资料


    __EOF__

  • 本文作者: 程序设计实验室
  • 本文链接: https://www.cnblogs.com/deali/p/16132905.html
  • 关于博主: 公众号:程序设计实验室,欢迎交流~
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    rust 开发入门
    9、定义错误页
    【深度学习】基于tensorflow的小型物体识别训练(数据集:CIFAR-10)
    el-table 默认数据选中优化版本
    别做重复低质的工作内容摸鱼了,18k强者分享自动化测试秘籍
    AWS SAA-C03 #157
    java串口通信(基于串口协议开发的私有协议,实现传输字符串与文件)
    扩散模型基本原理
    如何使用Java获取当前时间戳
    netcore基于asp.net的校园二手闲置商品交易系统
  • 原文地址:https://www.cnblogs.com/deali/p/16132905.html