【djangorestframework】8、Pagination(分页)

分页(Pagination)

  • Django提供了一些类类帮助你管理分页数据,也就是说,这些数据通过"前/下"链接被分割到多个页面。---Django文档
  • REST framework包含对自定义分页样式的支持。这允许你修改如何将大的结果集分成单个数据页面。
  • 分页API支持:
    • 分页链接是作为响应内容的一部分提供的。
    • 分页链接被包含在响应标头中,例如Content-Range或Link
  • 内置样式目前都使用被包含作为响应内容的一部分链接。使用可浏览API时,此样式更易于访问。
  • 只有在使用通用视图或视图集时,才会自定执行分页如果你使用常规APIView,则需要自己调用分页API以确保返回分页响应。有关示例,请参阅mixins.ListModelMixin和generic.GenericAPIView类的源代码。
  • 可以通过将分页类设置为None来关闭分页

设置分页样式(Setting the pagination style)

  • 可以使用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中使用相同的分页样式,尽管你可能希望在每个视图的基础上更改分页的各个方面,例如默认或最大页大小。

修改分页样式(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设置全局应用样式。例如:
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
}

API参考(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_params一起使用的值。用以请求集合的最终页面。默认为('last', )
      • template--在可浏览API中渲染分页控件时使用的模板的名称。可能会被覆盖以修改渲染样式,或设置为None以完全禁用HTML分页控件。默认为"rest_framework/pagination/numbers.html"

LimitOffsetPagination

  • 这种分页样式反映了查找多个数据库记录时使用的语法。客户端包括"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": [
       …
    ]
}
  • 设置(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--如果设置,则这是指示客户端可能请求的最大允许限度的数值。默认为None
      • template--在可浏览API中渲染分页控件时使用的模板的名称。可能会被覆盖以修改渲染样式,或设置为None以完全禁用HTML分页控件。默认为"rest_framework/pagination/numbers.html"

CursorPagination

  • 基于游标的分页提供了一个不透明的"游标"指示器,客户端可以使用该指示器来翻阅结果集。这种分页样式只提供正向和反向控件,并且不允许客户端导航到任意位置。
  • 基于游标的分页要求结果集中的项具有唯一且不变的排序。这种排序通常是记录上的创建时间戳,因为这提供了排序的一致性。
  • 基于游标的分页比其他方案更复杂。它还要求结果集提供固定顺序,并且不允许客户端任意索引到结果集。然而,它确实提供了以下好处:
    • 提供一致的分页视图。正确使用CursorPagination可确保客户端在分页记录时永远不会看到相同的项两次,即使在分页过程中其他客户端插入新项。
    • 支持使用非常大的数据集。对于极大的数据集,使用基于偏移的分页样式的分页可能变得低效或无法使用。基于游标的分页方案具有固定时间属性,并且不会随着数据集大小的增加而减慢。
细节和限制(Details and limitations)
  • 正确使用基于游标的分页需要稍微注意细节。你需要考虑希望该方案应用什么排序。默认是按"-created"排序。这假设在模型实例上必须有一个'created'时间戳字段,并且将显示'时间轴'样式的分页视图,其中最近添加的项是第一个。
  • 你可以通过覆盖分页类的'ordering'属性,或者将OrderingFilter过滤器类与CursorPagination一起使用来修改排序。当与OrderingFilter一起使用时,你应该强烈考虑限制用户可能排序的字段。
  • 正确使用游标分页应该有一个满足以下条件的排序字段:
    • 应该是一个不变的值,例如时间戳、slug或其他仅在创建时设置一次的字段。
    • 应该是唯一的,或者几乎是唯一的。毫秒精度时间戳就是很好的例子。游标分页的这种实现使用了智能的"位置+偏移"样式,允许它正确地支持非严格唯一的值作为排序。
    • 应该是可以强制为字符串的非空值。
    • 不应该是浮点数。精度误差容易导致不正确的结果。提示:使用小数代替。(如果你已经有了一个浮点字段,并且必须为它进行分页,那么这里能找到使用小数来限制精度的CurrPosiPrimes子类示例)
    • 该字段应具有数据库索引
  • 使用不满足这些约束的排序字段通常仍然有效,但是你将失去游标分页的一些好处。
设置(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"查询参数的名称的字符串值。默认为"cursor"
    • ordering--这应该是一个字符串或字符串列表,指示将应用基于游标的分页的字段。例如:ordering='slug'。默认为-created。该值还可以通过在视图上使用OrderingFiler来覆盖。
    • template--在可浏览API中渲染分页控件时使用的模板的名称。可能会被覆盖以修改渲染样式,或设置为None以完全禁用HTML分页控件。默认为"rest_frameworl/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方法可以使用它。

举个例子:

  • 假设我们想用一个修改后的格式替换默认分页输出样式,该格式包含嵌套"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,但这是可选的。

使用你的自定义分页类(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 framework提供的模式自动生成。此方法应具有以下签名:get_schema_fields(self, view)
  • 该方法应返回coreapi.Field实例的列表。

HTML分页控件(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设置键,以将你的自定义类用作默认分页样式。

低级API(Low-level API)

  • 用于确定分页类是否显示控件的低级API在分页实例上公开为display_page_controls属性。如果需要显示HTML分页控件,则应在paginate_queryset方法中将自定义分页类设置为True
  • .to_html()和.get_html_context()方法也可以在自定义分页类中重写,以便进一步自定义控件的渲染方式。

第三方包(Third party packages)

  • 以下是可用的第三方包

DRF-extensions

  • DRF-extensions包包括PaginateByMax混合类,它允许你的API客户端指定?page_size=max以获得允许的最大页面大小

drf-proxy-pagination

  • drf-proxy-pagination包中包含ProxyPagination类,允许选择带有查询参数的分页类

link-header-pagination

  • django-rest-framework-link-header-pagination包中包含LinkHeaderPagination类,它通过GitHub开发者文档中描述的HTTP Link标头提供分页。
posted @ 2022-04-25 16:02  郭祺迦  阅读(480)  评论(0)    收藏  举报