Django提供了一些类来帮助您管理分页数据 - 即分布在多个页面上的数据,带有“上一页/下一页”链接。
REST框架包括对可自定义分页样式的支持。这允许您修改将大型结果集拆分为单个数据页的方式。
分页API可以支持:
- 分页链接是作为响应内容的一部分提供的。
- 响应标头中包含的分页链接,例如Content-Range或Link。
内置样式目前都使用包含在响应内容中的链接。使用可浏览API时,此样式更易于访问。
只有在使用通用视图或视图集时( generic views or viewsets),才会自动执行分页。如果您使用常规APIView,则需要自己调用分页API以确保返回分页响应。有关示例,请参阅mixins.ListModelMixin和generics.GenericAPIView类的源代码。
可以通过将分页类设置为“None”来关闭分页。
设置分页样式
可以使用DEFAULT_PAGINATION_CLASS和PAGE_SIZE设置键全局设置分页样式。例如,要使用内置限制/偏移分页,您可以执行以下操作:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 100
}
请注意,您需要同时设置分页类和应使用的页面大小。 DEFAULT_PAGINATION_CLASS和PAGE_SIZE都默认为None。
您还可以使用pagination_class属性在单个视图上设置分页类。通常,您希望在整个API中使用相同的分页样式,尽管您可能希望基于每个视图改变分页的各个方面,例如默认或最大页面大小。
修改分页样式
如果要修改分页样式的特定方面,则需要覆盖其中一个分页类,并设置要更改的属性。
class LargeResultsSetPagination(PageNumberPagination):
page_size = 1000
page_size_query_param = 'page_size'
max_page_size = 10000
class StandardResultsSetPagination(PageNumberPagination):
page_size = 100
page_size_query_param = 'page_size'
max_page_size = 1000
然后,您可以使用.pagination_class属性将新样式应用于视图:
class BillingRecordsView(generics.ListAPIView):
queryset = Billing.objects.all()
serializer_class = BillingRecordsSerializer
pagination_class = LargeResultsSetPagination
或者使用DEFAULT_PAGINATION_CLASS设置键全局应用样式。例如:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
}
API Reference
PageNumberPagination
此分页样式在请求查询参数中接受单个数字页码。
Request:
GET https://api.example.org/accounts/?page=4
Response:
HTTP 200 OK
{
"count": 1023
"next": "https://api.example.org/accounts/?page=5",
"previous": "https://api.example.org/accounts/?page=3",
"results": [
…
]
}
Setup
要全局启用PageNumberPagination样式,请使用以下配置,并根据需要设置PAGE_SIZE:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100
}
在GenericAPIView子类上,您还可以设置pagination_class属性以基于每个视图选择PageNumberPagination。
Configuration
PageNumberPagination类包含许多可以重写以修改分页样式的属性。
要设置这些属性,您应该覆盖PageNumberPagination类,然后启用上面的自定义分页类。
- django_paginator_class - 要使用的Django Paginator类。默认是django.core.paginator.Paginator,对于大多数用例应该没问题。
- page_size - 表示页面大小的数值。如果设置,则会覆盖PAGE_SIZE设置。默认为与PAGE_SIZE设置键相同的值。
- page_query_param - 一个字符串值,指示用于分页控件的查询参数的名称。
- page_size_query_param - 如果设置,则这是一个字符串值,指示允许客户端基于每个请求设置页面大小的查询参数的名称。默认为None,表示客户端可能无法控制请求的页面大小。
- max_page_size - 如果设置,则这是一个数值,指示允许的最大请求页面大小。仅当还设置了page_size_query_param时,此属性才有效。
- last_page_strings - 字符串值的列表或元组,指示可与page_query_param一起使用以请求集合中的最终页面的值。默认为('last',)
- template - 在可浏览API中呈现分页控件时要使用的模板的名称。可以重写以修改呈现样式,或者设置为None以完全禁用HTML分页控件。默认为“rest_framework / pagination / numbers.html”。
LimitOffsetPagination
这种分页样式反映了查找多个数据库记录时使用的语法。 客户端包括“limit”和“offset”查询参数。 限制表示要返回的最大项目数,相当于其他样式中的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": [
…
]
}
Setup
要全局启用LimitOffsetPagination样式,请使用以下配置:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'
}
或者,您也可以设置PAGE_SIZE键。 如果还使用了PAGE_SIZE参数,则limit查询参数将是可选的,并且客户端可以省略。
在GenericAPIView子类上,您还可以设置pagination_class属性以基于每个视图选择LimitOffsetPagination。
Configuration
LimitOffsetPagination类包含许多可以重写以修改分页样式的属性。
要设置这些属性,您应该覆盖LimitOffsetPagination类,然后启用上面的自定义分页类。
- default_limit - 一个数值,指示客户端在查询参数中未提供限制时使用的限制。 默认为与PAGE_SIZE设置键相同的值。
- limit_query_param - 一个字符串值,指示“limit”查询参数的名称。 默认为“limit”。
- offset_query_param - 一个字符串值,指示“offset”查询参数的名称。 默认为'offset'。
- max_limit - 如果设置,这是一个数值,表示客户端可能请求的最大允许限制。 默认为无。
- template - 在可浏览API中呈现分页控件时要使用的模板的名称。 可以重写以修改呈现样式,或者设置为None以完全禁用HTML分页控件。 默认为“rest_framework / pagination / numbers.html”。
CursorPagination
基于光标的分页呈现不透明的“光标”指示符,客户端可以使用该指示符来翻阅结果集。 这种分页样式仅呈现正向和反向控件,并且不允许客户端导航到任意位置。
基于游标的分页要求结果集中的项具有唯一且不变的排序。 这种排序通常可以是记录上的创建时间戳,因为这提供了一致的分页排序。
基于游标的分页比其他方案更复杂。 它还要求结果集呈现固定的排序,并且不允许客户端任意索引到结果集中。 但它确实提供了以下好处:
- 提供一致的分页视图。 正确使用CursorPagination可确保客户端在分页记录时永远不会看到相同的项目,即使在分页过程中其他客户端插入新项目时也是如此。
- 支持使用非常大的数据集。 对于极大的数据集,使用基于偏移的分页样式的分页可能变得低效或无法使用。 基于游标的分页方案具有固定时间属性,并且不会随着数据集大小的增加而减慢。
Details and limitations
正确使用基于光标的分页需要注意细节。 您需要考虑您希望应用该方案的顺序。 默认是按“-created”排序。 这假定模型实例上必须存在“已创建”的时间戳字段,并且将呈现“时间轴”样式的分页视图,其中最近添加的项目是第一个。
您可以通过覆盖分页类的“ordering”属性,或者将OrderingFilter过滤器类与CursorPagination一起使用来修改排序。 与OrderingFilter一起使用时,您应该强烈考虑限制用户可能订购的字段。
正确使用游标分页应该有一个满足以下条件的排序字段:
- 应该是一个不变的值,例如时间戳,slug或其他仅在创建时设置一次的字段。
- 应该是独一无二的,或几乎是独特的 毫秒精度时间戳就是一个很好的例子。 光标分页的这种实现使用智能“位置加偏移”样式,允许它正确支持非严格唯一值作为排序。
- 应该是一个可以强制转换为字符串的非可空值。
- 不应该是浮动的。 精度错误很容易导致错误的结果。 提示:改为使用小数。 (如果您已经有一个float字段并且必须对其进行分页,则此处提供了使用小数来限制精度的示例CursorPagination子类。)
- 该字段应具有数据库索引。
使用不满足这些约束的排序字段通常仍然有效,但是您将失去光标分页的一些好处。
有关我们用于游标分页的实现的更多技术细节,“为Disqus API构建游标”博客文章提供了基本方法的良好概述。
Setup
要全局启用CursorPagination样式,请使用以下配置,根据需要修改PAGE_SIZE:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination',
'PAGE_SIZE': 100
}
在GenericAPIView子类上,您还可以设置pagination_class属性以基于每个视图选择CursorPagination。
Configuration
CursorPagination类包含许多可以重写以修改分页样式的属性。
要设置这些属性,您应该覆盖CursorPagination类,然后启用上面的自定义分页类。
- page_size =表示页面大小的数值。 如果设置,则会覆盖PAGE_SIZE设置。 默认为与PAGE_SIZE设置键相同的值。
- cursor_query_param =表示“cursor”查询参数名称的字符串值。 默认为'光标'。
- ordering =这应该是一个字符串或字符串列表,指示将应用基于光标的分页的字段。 例如:ordering ='slug'。 默认为-created。 也可以通过在视图上使用OrderingFilter来覆盖此值。
- template =在可浏览API中呈现分页控件时要使用的模板的名称。 可以重写以修改呈现样式,或者设置为None以完全禁用HTML分页控件。 默认为“rest_framework / pagination / previous_and_next.html”。
Custom pagination styles
要创建自定义分页序列化程序类,您应该继承pagination.BasePagination并覆盖paginate_queryset(self,queryset,request,view = None)和get_paginated_response(self,data)方法:
- paginate_queryset方法传递给初始查询集,并且应该返回一个只包含所请求页面中的数据的可迭代对象。
- get_paginated_response方法传递序列化页面数据,并应返回Response实例。
请注意,paginate_queryset方法可以在分页实例上设置状态,稍后可以由get_paginated_response方法使用该状态。
Example
假设我们想要使用包含嵌套“链接”键下的下一个和上一个链接的修改格式替换默认分页输出样式。我们可以像这样指定一个自定义分页类:
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
})
然后我们需要在配置中设置自定义类:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPagination',
'PAGE_SIZE': 100
}
请注意,如果您关心如何在可浏览API的响应中显示键的顺序,您可以选择在构造分页响应的主体时使用OrderedDict,但这是可选的。
Using your custom pagination class
要默认使用自定义分页类,请使用DEFAULT_PAGINATION_CLASS设置:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination',
'PAGE_SIZE': 100
}
列表端点的API响应现在将包含链接头,而不是将分页链接作为响应主体的一部分包括在内,例如:
Pagination & schemas
您还可以通过实现get_schema_fields()方法使分页控件可用于REST框架提供的模式自动生成。此方法应具有以下签名:
get_schema_fields(self, view)
该方法应返回coreapi.Field实例的列表。
HTML pagination controls
默认情况下,使用分页类将导致HTML分页控件显示在可浏览的API中。 有两种内置显示样式。 PageNumberPagination和LimitOffsetPagination类显示包含上一个和下一个控件的页码列表。 CursorPagination类显示更简单的样式,仅显示上一个和下一个控件。
Customizing the controls
您可以覆盖呈现HTML分页控件的模板。两种内置样式是:
- rest_framework/pagination/numbers.html
- rest_framework/pagination/previous_and_next.html
在全局模板目录中提供具有这些路径之一的模板将覆盖相关分页类的默认呈现。
或者,您可以通过继承现有类来完全禁用HTML分页控件,将template = None设置为类的属性。 然后,您需要配置DEFAULT_PAGINATION_CLASS设置键以将自定义类用作默认分页样式。
Low-level API
用于确定分页类是否应显示控件的低级API在分页实例上公开为display_page_controls属性。 如果需要显示HTML分页控件,则应在paginate_queryset方法中将自定义分页类设置为True。
.to_html()和.get_html_context()方法也可以在自定义分页类中重写,以进一步自定义控件的呈现方式。
Third party packages
还提供以下第三方软件包。
DRF-extensions
DRF-extensions软件包包含一个PaginateByMaxMixin mixin类,允许您的API客户端指定?page_size = max
以获取允许的最大页面大小。
drf-proxy-pagination
drf-proxy-pagination包中包含一个ProxyPagination类,允许选择带有查询参数的分页类。
link-header-pagination
django-rest-framework-link-header-pagination包中包含一个LinkHeaderPagination类,它通过Github开发者文档中描述的HTTP Link头提供分页。