官方文档
https://q1mi.github.io/Django-REST-framework-documentation/api-guide/pagination_zh/
B站没有好的教学视频,不建议看,直接看官方文档吧。
此分页样式接受请求查询参数中的单个数字页码。
Request:
GET https://api.example.org/accounts/?page=4
Response:
{
"count": 1023
"next": "https://api.example.org/accounts/?page=5",
"previous": "https://api.example.org/accounts/?page=3",
"results": [
…
]
}
Settings:
全局启用 PageNumberPagination
样式,请使用以下配置,并根据需要设置 PAGE_SIZE
:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100
}
自定义一个继承自PageNumberPagination的分页器,然后在里面设置page_size,如下:
class LargeResultsSetPagination(PageNumberPagination):
page_size = 1000
page_size_query_param = 'page_size' # 非必需
max_page_size = 10000 # 非必需
如果只想用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)
这种分页样式反映了查找多个数据库记录时使用的语法。客户端包括“limit”和“offset”查询参数。limit指示要返回的项目的最大数目,这相当于其他样式中的 page_size
。offset指示查询相对于完整的未分页项的起始位置。
Request:
GET https://api.example.org/accounts/?limit=100&offset=400
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": [
…
]
}
Settings:
为了全局启用 LimitOffsetPagination
样式,请使用以下配置:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 10
}
ps:又是一个易错点,虽然limitoffsetpagination用的是limit,但是全局设置时还是要设置PAGE_SIZE。。
自定义一个继承自LimitOffsetPagination
的分页器,然后在里面设置limit,如下:
class CustomLimitOffsetPagination(LimitOffsetPagination):
default_limit = 5 # 自定义默认每页显示的数量,一定要给
max_limit = 20 # 自定义每页显示的最大数量,非必需
如果只想用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)
像是如上的
{
"count": 1023
"next": "https://api.example.org/accounts/?page=5",
"previous": "https://api.example.org/accounts/?page=3",
"results": [
…
]
}
{
"count": 1023
"next": "https://api.example.org/accounts/?limit=100&offset=500",
"previous": "https://api.example.org/accounts/?limit=100&offset=300",
"results": [
…
]
}
都是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)
假设我们想用一个修改过的格式替换默认的分页输出样式,该格式在嵌套的“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
})
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.+)" )
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)