pagination.py

Pagination

Django提供了一些类来帮助您管理分页数据 - 即分布在多个页面上的数据,使用“上一页/下一页”链接。

Django documentation

REST框架包括对可自定义分页样式的支持。 这允许您修改将大型结果集拆分为单个数据页的方式。

分页API可以支持:

  • 分页链接是作为响应内容的一部分提供的。
  • 响应头中包含的分页链接,例如Content-RangeLink

内置样式目前都使用包含在响应内容中的链接。 使用可浏览API时,此样式更易于访问。

只有在使用通用视图或视图集时,才会自动执行分页。 如果您使用常规的APIView,则需要自己调用分页API以确保返回分页响应。 有关示例,请参阅mixins.ListModelMixingenerics.GenericAPIView类的源代码。

可以通过将分页类设置为None来关闭分页。

Setting the pagination style

可以使用DEFAULT_PAGINATION_CLASSPAGE_SIZE设置键全局设置分页样式。 例如,要使用内置限制/偏移分页,您可以执行以下操作:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 100
}

请注意,您需要设置分页类和应该使用的页面大小。 默认情况下,DEFAULT_PAGINATION_CLASSPAGE_SIZE都是None

您还可以使用pagination_class属性在单个视图上设置分页类。 通常,您希望在整个API中使用相同的分页样式,尽管您可能希望基于每个视图改变分页的各个方面,例如默认或最大页面大小。

Modifying the pagination style

如果要修改分页样式的特定方面,则需要覆盖其中一个分页类,并设置要更改的属性。

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设置键全局应用样式。 For example:

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 - If set, this is a string value indicating the name of a query parameter that allows the client to set the page size on a per-request basis. Defaults to None, indicating that the client may not control the requested page size.
  • max_page_size - If set, this is a numeric value indicating the maximum allowable requested page size. This attribute is only valid if page_size_query_param is also set.
  • last_page_strings - A list or tuple of string values indicating values that may be used with the page_query_param to request the final page in the set. Defaults to ('last',)
  • template - The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to None to disable HTML pagination controls completely. Defaults to "rest_framework/pagination/numbers.html".

LimitOffsetPagination

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

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 - 表示“限制”查询参数名称的字符串值。 Defaults to 'limit'.
  • offset_query_param - 表示“偏移”查询参数名称的字符串值。 Defaults to 'offset'.
  • max_limit - 如果设置,这是一个数值,表示客户端可能请求的最大允许限制。 Defaults to None.
  • template - 在可浏览API中呈现分页控件时要使用的模板的名称。 可以重写以修改呈现样式,或设置为None以完全禁用HTML分页控件。 Defaults to "rest_framework/pagination/numbers.html".

CursorPagination

基于光标的分页呈现不透明的“光标”指示符,客户端可以使用该指示符来翻阅结果集。 此分页样式仅显示前向和后退控件,并且不允许客户端导航到任意位置。

基于游标的分页要求结果集中的项具有唯一且不变的排序。 此排序通常可能是记录上的创建时间戳,因为这提供了一致的分页排序。

基于游标的分页比其他方案更复杂。 它还要求结果集呈现固定的排序,并且不允许客户端任意索引到结果集中。 但它确实提供了以下好处:

  • 提供一致的分页视图。 正确使用CursorPagination确保客户端在分页记录时永远不会看到相同的项目,即使在分页过程中其他客户端插入新项目时也是如此。
  • 支持使用非常大的数据集。 对于极大的数据集,使用基于偏移的分页样式的分页可能变得低效或无法使用。 基于游标的分页方案具有固定时间属性,并且不会随着数据集大小的增加而减慢。

Details and limitations

正确使用基于光标的分页需要注意细节。 您需要考虑您希望应用该方案的顺序。 默认是按“ - created”排序。 这假设在模型实例上必须有一个“创建的”时间戳字段,并且将呈现“时间轴”样式的分页视图,其中最近添加的项目是第一个。

您可以通过覆盖分页类上的'ordering'属性,或者使用OrderingFilter过滤器类以及CursorPagination来修改排序。 OrderingFilter一起使用时,您应该强烈考虑限制用户可能订购的字段。

正确使用游标分页应该有一个满足以下条件的排序字段:

  • 应该是一个不变的值,例如时间戳,slug或其他仅在创建时设置一次的字段。
  • 应该是独特的,或几乎是独一无二的 毫秒精度时间戳就是一个很好的例子。 光标分页的这种实现使用智能“位置加偏移”样式,允许它正确支持非严格唯一值作为排序。
  • 应该是一个可以强制转换为字符串的非可空值。
  • 不应该是浮动的。 精度错误很容易导致错误的结果。 提示:改用小数。 (如果您已经有一个浮点字段并且必须对其进行分页,则可以使用示例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”查询参数名称的字符串值。 Defaults to 'cursor'.
  • ordering =这应该是一个字符串或字符串列表,表示将应用基于光标的分页的字段。 For example: ordering = 'slug'. Defaults to -created. 也可以通过在视图上使用OrderingFilter来覆盖此值。
  • template =在可浏览API中呈现分页控件时要使用的模板的名称。 可以重写以修改呈现样式,或设置为None以完全禁用HTML分页控件。 Defaults to "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响应现在将包含Link标头,而不是将分页链接包含在响应主体的一部分中,例如:

Pagination & schemas

您还可以通过实现get_schema_fields()方法,使分页控件可用于REST框架提供的模式自动生成。 此方法应具有以下签名:

get_schema_fields(self, view)

该方法应返回coreapi.Field实例的列表。


Link Header

A custom pagination style, using the 'Link' header'


HTML pagination controls

默认情况下,使用分页类将导致HTML分页控件显示在可浏览的API中。 有两种内置显示样式。 PageNumberPaginationLimitOffsetPagination类显示包含上一个和下一个控件的页码列表。 CursorPagination类显示更简单的样式,仅显示上一个和下一个控件。

Customizing the controls

您可以覆盖呈现HTML分页控件的模板。 两种内置样式是:

  • rest_framework/pagination/numbers.html
  • rest_framework/pagination/previous_and_next.html

Providing a template with either of these paths in a global template directory will override the default rendering for the relevant pagination classes.

Alternatively you can disable HTML pagination controls completely by subclassing on of the existing classes, setting template = None as an attribute on the class. You'll then need to configure your DEFAULT_PAGINATION_CLASS settings key to use your custom class as the default pagination style.

Low-level API

用于确定分页类是否应显示控件的低级API在分页实例上公开为display_page_controls属性。 如果需要显示HTML分页控件,则应在paginate_queryset方法中将自定义分页类设置为True

.to_html().get_html_context()方法也可以在自定义分页类中重写,以进一步自定义控件的呈现方式。


Third party packages

The following third party packages are also available.

DRF-extensions

The DRF-extensions package includes a PaginateByMaxMixin mixin class that allows your API clients to specify ?page_size=max to obtain the maximum allowed page size.

drf-proxy-pagination

The drf-proxy-pagination package includes a ProxyPagination class which allows to choose pagination class with a query parameter.

The django-rest-framework-link-header-pagination package includes a LinkHeaderPagination class which provides pagination via an HTTP Link header as desribed in Github's developer documentation.