当前位置:   article > 正文

DRF分页器(Django Restful Framework)

DRF分页器(Django Restful Framework)

资料推荐

官方文档
https://q1mi.github.io/Django-REST-framework-documentation/api-guide/pagination_zh/
B站没有好的教学视频,不建议看,直接看官方文档吧。

PageNumberPagination

此分页样式接受请求查询参数中的单个数字页码。
Request:

GET https://api.example.org/accounts/?page=4
  • 1

Response:

{
    "count": 1023
    "next": "https://api.example.org/accounts/?page=5",
    "previous": "https://api.example.org/accounts/?page=3",
    "results": [
       …
    ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Settings:

全局设置

全局启用 PageNumberPagination 样式,请使用以下配置,并根据需要设置 PAGE_SIZE

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 100
}
  • 1
  • 2
  • 3
  • 4

单视图设置(重点!)

自定义继承子类

自定义一个继承自PageNumberPagination的分页器,然后在里面设置page_size,如下:

class LargeResultsSetPagination(PageNumberPagination):
    page_size = 1000
    page_size_query_param = 'page_size' # 非必需
    max_page_size = 10000 # 非必需
  • 1
  • 2
  • 3
  • 4

重写get_paginate_by方法

如果只想用PageNumberPagination本身,那么需要通过重写get_paginate_by方法来设置page_size。

class YourView(generics.ListAPIView):
    queryset = YourModel.objects.all()
    serializer_class = YourSerializer

    # 使用官方的 PageNumberPagination 类
    pagination_class = PageNumberPagination

    # 覆盖默认的分页设置
    def get_paginate_by(self, queryset):
        return self.request.query_params.get('page_size', 5)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

LimitOffsetPagination

这种分页样式反映了查找多个数据库记录时使用的语法。客户端包括“limit”和“offset”查询参数。limit指示要返回的项目的最大数目,这相当于其他样式中的 page_size。offset指示查询相对于完整的未分页项的起始位置。
Request:

GET https://api.example.org/accounts/?limit=100&offset=400
  • 1

Response:

HTTP 200 OK
{
    "count": 1023
    "next": "https://api.example.org/accounts/?limit=100&offset=500",
    "previous": "https://api.example.org/accounts/?limit=100&offset=300",
    "results": [
       …
    ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Settings:

全局设置

为了全局启用 LimitOffsetPagination样式,请使用以下配置:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
	'PAGE_SIZE': 10
}
  • 1
  • 2
  • 3
  • 4

ps:又是一个易错点,虽然limitoffsetpagination用的是limit,但是全局设置时还是要设置PAGE_SIZE。。

单视图设置(重点!)

自定义继承子类实现

自定义一个继承自LimitOffsetPagination的分页器,然后在里面设置limit,如下:

class CustomLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 5  # 自定义默认每页显示的数量,一定要给
    max_limit = 20  # 自定义每页显示的最大数量,非必需
  • 1
  • 2
  • 3

重写get_paginate_by

如果只想用LimitOffsetPagination本身,那么需要通过重写get_paginate_by方法来设置limit。

from rest_framework import generics
from rest_framework.pagination import LimitOffsetPagination

class YourView(generics.ListAPIView):
    queryset = YourModel.objects.all()
    serializer_class = YourSerializer
    pagination_class = LimitOffsetPagination  # 使用 LimitOffsetPagination

    # 覆盖默认的分页设置
    def get_paginate_by(self, queryset):
        return self.request.query_params.get('limit', 10)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

获取分页输出样式/具体如何使用分页器(重点!)

像是如上的

{
    "count": 1023
    "next": "https://api.example.org/accounts/?page=5",
    "previous": "https://api.example.org/accounts/?page=3",
    "results": [
       …
    ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
{
    "count": 1023
    "next": "https://api.example.org/accounts/?limit=100&offset=500",
    "previous": "https://api.example.org/accounts/?limit=100&offset=300",
    "results": [
       …
    ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

都是pagenumberpagination、limitoffsetpagination等官方分页器通过get_paginated_response返回的默认的分页样式。

具体使用如下:

class CustomLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 5  # 自定义默认每页显示的数量

class YourView(generics.ListAPIView):
    queryset = YourModel.objects.all()
    serializer_class = YourSerializer
    pagination_class = CustomLimitOffsetPagination  # 使用自定义分页类

    def get(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
  • 16
  • 17
  • 18

自定义分页输出样式(重写get_paginated_response方法!!重要!)

假设我们想用一个修改过的格式替换默认的分页输出样式,该格式在嵌套的“links”键中包含下一页和上一页的链接。我们就需要自定义分页器,并重写get_paginated_response方法

class CustomPagination(pagination.PageNumberPagination):
    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
        })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

最常使用场景举例

from rest_framework.pagination import LimitOffsetPagination

from utils import ThirdPartResponse


class TaskPagination(LimitOffsetPagination):
    default_limit = 5  # 自定义默认每页显示的数量,一定要给。及时后续会在请求参数中拿到limit,也一定要给

    def get_paginated_response(self, data):
        return ThirdPartResponse(data={"total": self.count, "data": data})

@action(detail=False, methods=["get"], url_path="list-by-template/(?P<template_id>.+)")
def list_by_template(self, request, template_id=None):
    """
    根据template_id过滤任务列表
    """
    if template_id is None:
        message = "template_id is required"
        logger.error(message)
        return ThirdPartResponse(result=False, message=message)
    tasks = self.queryset.filter(template_id=template_id)

    paginator = TaskPagination()
    page = paginator.paginate_queryset(tasks, request)
    if page is not None:
        serializer = self.get_serializer(page, many=True)
        return paginator.get_paginated_response(serializer.data)
    serializer = self.get_serializer(tasks, many=True)
    return Response(serializer.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
  • 29
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/840342
推荐阅读
相关标签
  

闽ICP备14008679号