点击跳转到 Rest-Framework 专栏目录
当你的 API 返回大数据的时候, 这时候你可能需要用到分页, 分页 API 可以支持以下任一功能:
- 作为响应内容的一部分, 并提供分页链接
- 响应头包含分页链接, 例如
Content-Range
或者Link
当前内置样式均使用作为响应内容一部分包含的链接样式, 此样式更易于访问。
仅在使用通用视图或视图集时才自动执行分页, 如果您使用的是常规 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
在单个视图类中指定分页类, 通常情况下, 需要保证整个系统的分页统一和样式统一, 尽管在一些特殊的情况下, 如单独设置页面返回数据的最大值或最小值。
修改分页样式
如果你需要修改默认的分页样式, 则需要覆盖其中的一个分页类, 并覆盖其中的属性值:
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'
}
PageNumberPagination
此分页样式在请求时, 接受一个单数字页码。
请求:
GET https://api.example.org/accounts/?page=4
响应:
HTTP 200 OK
{
"count": 1023,
"next": "https://api.example.org/accounts/?page=5",
"previous": "https://api.example.org/accounts/?page=3",
"results": [
…
]
}
如果使用该样式, 请使用以下配置, 并根据你的需求设置 PAGE_SIZE
的数值:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100
}
在 GenericAPIView
子类上您还可以设置 pagination_class
属性, 以基于每个视图进行 PageNumberPagination
选择。
所述 PageNumberPagination
类包括多个可重写修改分页样式属性, 要设置这些属性, 您应该覆盖 PageNumberPagination
类, 然后如上所述启用您的自定义分页类。
django_paginator_class
要使用的 Django 分页类, 默认值为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
查询参数, 该限制指示要返回的最大项目数, 偏移量指示查询相对于完整的未标记项集的起始位置。
简而言之, 在你使用 limit=100&offset=2
的数据查询时, 你的偏移量是 100
, 你的查询数据起始位置是 limit * (offset - 1)
, 反映了你在查询数据流中的起始位置以及终止位置, 类似于列表切片。
请求:
GET https://api.example.org/accounts/?limit=100&offset=400
响应:
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": [
…
]
}
若是你需要全局性启用 LimitOffsetPagination
样式, 请使用以下配置:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'
}
您也可以选择性设置 PAGE_SIZE
数值, 如果还使用了该 PAGE_SIZE
参数, 则 limit
查询参数将是可选的, 并且客户端可以将其省略。
在 GenericAPIView
子类上, 您还可以设置 pagination_class
属性, 以基于每个视图进行 LimitOffsetPagination
选择。
所述 LimitOffsetPagination
类包括多个可重写修改分页样式属性, 要设置这些属性, 您应该覆盖 LimitOffsetPagination
类, 然后如上所述启用您的自定义分页类。
default_limit
一个数字值, 指示客户端未在查询参数中提供限制时使用的限制, 默认值为PAGE_SIZE
的值limit_query_param
字符串值, 指示limit
查询参数的名称, 默认为'limit'
offset_query_param
一个字符串值, 指示offset
查询参数的名称, 默认为'offset'
max_limit
如果设置了此值, 则该值表示客户端可能请求的最大允许限制, 默认为None
template
在可浏览的 API 中呈现分页控件时要使用的模板的名称, 可以重写以修改呈现样式, 或设置为None
完全禁用 HTML 分页控件, 默认为"rest_framework/pagination/numbers.html"
CursorPagination
基于游标的分页提供了一个不透明的“游标”指示器, 客户端可以使用它对结果集进行分页, 这种分页样式只显示前进和后退的控件, 并且不允许客户端导航到任意位置。
基于光标的分页要求结果集中的项具有唯一的、不变的顺序, 此顺序通常可能是记录上的创建时间戳, 因为它提供了一个一致的顺序来分页。
基于光标的分页比其他方案更复杂, 它还要求结果集呈现固定的顺序, 并且不允许客户端任意索引到结果集, 但是它确实提供了以下好处:
- 提供一致的分页视图, 如果使用得当
CursorPagination
可以确保客户端在翻阅记录时永远不会看到相同的项目两次, 即使在分页过程中其他客户端插入了新项目时也是如此 - 支持使用非常大的数据集, 对于非常大的数据集, 如果使用基于偏移的分页样式的分页, 可能会变得效率低下或无法使用, 相反基于游标的分页方案具有固定时间属性, 并且不会随着数据集大小的增加而变慢
正确使用基于游标的分页需要稍微注意细节, 您需要考虑要针对该方案应用哪种排序, 默认设置为 "-created"
, 但是在模型实例上必须有一个 "created"
时间戳字段, 并且将呈现一个 "timeline"
样式的分页视图, 其中最新添加的项在前面。
正确使用游标分页应具有满足以下条件的排序字段:
- 创建时应为不变的值, 例如时间戳、段标或仅设置一次的其他字段
- 应该是唯一的, 或者几乎是唯一的, 毫秒精度时间戳就是一个很好的例子, 游标分页的这种实现使用了一种智能的 “位置加偏移” 样式, 允许它正确地支持不严格唯一的值作为排序值
- 应该是可以强制转换为字符串的非空值
- 不应该是浮点数, 精度误差很容易导致错误的结果, 提示:请改用小数 (如果您已经有一个 float 字段, 并且必须对此进行分页, 则此处提供了一个使用小数来限制精度的示例
CursorPagination
子类) - 该字段应具有数据库索引
使用不满足这些约束的排序字段通常仍然可以使用, 但是您将失去光标分页的一些好处。
有关用于游标分页的实现的更多技术细节, 博客文章 “为Disqus API建立游标” 对基本方法进行了很好的概述。
要全局启用 CursorPagination
样式, 请使用以下配置, PAGE_SIZE
根据需要进行修改:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination',
'PAGE_SIZE': 100
}
在 GenericAPIView
子类上, 您还可以设置 pagination_class
属性以基于每个视图进行 CursorPagination
选择。
所述 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"
自定义分页
要创建自定义的分页序列化程序类, 您应该继承 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
方法使用。
假设我们想用修改后的格式替换默认的分页输出样式, 该格式在嵌套的 "links"
键中包含下一个和上一个链接, 我们可以这样指定一个自定义分页类:
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
, 并且这是可选的。
使用自定义分页类
要在默认情况下使用自定义分页类, 请使用以下 DEFAULT_PAGINATION_CLASS
设置:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination',
'PAGE_SIZE': 100
}
列表端点的 API 响应现在将包含 Link
标头, 而不是将分页链接作为响应主体的一部分, 例如:
分页和模式
您还可以通过实现 get_schema_fields()
方法, 使分页控件可用于 REST 框架提供的模式自动生成, 此方法应具有以下签名:
get_schema_fields(self, view)
该方法应返回 coreapi.Field
实例列表。
HTML 分页控件
默认情况下使用分页类将导致 HTML 分页控件显示在可浏览的 API 中, 有两种内置显示样式, PageNumberPagination
和 LimitOffsetPagination
类显示带有上一个和下一个控件的页码列表, CursorPagination
类显示的样式更简单, 只显示上一个和下一个控件。
自定义控件
您可以覆盖呈现 HTML 分页控件的模板, 两种内置样式是:
rest_framework/pagination/numbers.html
rest_framework/pagination/previous_and_next.html
在全局模板目录中提供具有这些路径之一的模板, 将覆盖相关分页类的默认呈现。
另外您可以通过将现有类的子类设置 template=None
为该类的属性, 来完全禁用 HTML 分页控件, 然后您需要配置 DEFAULT_PAGINATION_CLASS
设置, 以将自定义类用作默认的分页样式。
分页实例上的 display_page_controls
用于确定分页类是否应显示控件的低级 API, 如果自定义分页类需要显示 HTML 分页控件, 则应在 paginate_queryset
方法中将其设置为 True
。
为了进一步自定义控件的呈现方式, 还可以在自定义分页类中重写 .to_html()
和 .get_html_context()
方法。
扩展
-
DRF-extensions
该
DRF-extensions
软件包包括一个PaginateByMaxMixinmixin
类, 该类允许您的 API 客户端指定?page_size=max
以获得最大允许页面大小 -
drf-proxy-pagination
该
drf-proxy-pagination
软件包包括一个ProxyPagination
类, 该类允许选择带有查询参数的分页类 -
link-header-pagination
该
django-rest-framework-link-header-pagination
软件包包括一个LinkHeaderPagination
类, 该类通过 Github 开发人员文档中 Link 描述的 HTTP 标头提供分页
今天的文章Rest-framework专栏讲解(二十三):Pagination分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:http://bianchenghao.cn/22238.html