一、分页配置
在系统开发中,分页一般都是必不可少的功能。REST framework包含对可定制分页样式的支持,这使你可以将较大的结果集分成单独的数据页面。
需要知道是,分页仅在你使用通用视图或视图集时自动执行。如果你使用的是常规APIView
,则需要自己调用分页 API 以确保返回分页响应。示例请参阅mixins.ListModelMixin
和generics.GenericAPIView
类的 API 介绍。
一般,直接使用ModelViewSet
类即可,此类继承自 GenericAPIView
,并通过混合各种 mixin 类的行为来包含各种操作的实现。ModelViewSet
提供的操作有 .list()
, .retrieve()
, .create()
, .update()
, .partial_update()
, 和 .destroy()
。
由于 ModelViewSet
类继承自 GenericAPIView
,因此通常需要提供至少 queryset
和 serializer_class
属性。例如:
1 2 3 4 5 6 7 |
class AccountViewSet(viewsets.ModelViewSet): """ 用于查看和编辑 Account """ queryset = Account.objects.all() serializer_class = AccountSerializer permission_classes = [IsAccountAdminOrReadOnly] |
分页样式设置可以使用DEFAULT_PAGINATION_CLASS
和PAGE_SIZE
在setting.py文件中全局设置。
例如,要使用内置的 limit/offset 分页,你可以这样做:
1 2 3 4 |
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 100 } |
请注意,你需要设置分页类和使用的页面大小。默认情况下,DEFAULT_PAGINATION_CLASS
和PAGE_SIZE
都是None
,为None
时表示关闭分页。
除了在全局设置外,你还可以使用pagination_class
属性在单个视图上设置分页类。通常,你希望在整个 API 中使用相同的分页样式,但你可能希望在每个视图的基础上更改分页的各个方面,例如默认或最大页面大小等。如果要修改分页样式的特定方面,则需要继承其中一个分页类,并设置要更改的属性。
1 2 3 4 5 6 7 8 9 10 |
from rest_framework.pagination import PageNumberPagination class StandardResultsSetPagination(PageNumberPagination): """ 配置分页规则 """ page_size = 2 page_size_query_param = 'page_size' page_query_param = 'page' max_page_size = 100 |
PageNumberPagination类包括可以覆盖以修改分页样式的许多属性,要设置这些属性,应继承PageNumberPagination类,然后如上所示启用自定义分页类。
- django_paginator_class:使用的Django Paginator类,默认是django.core.paginator.Paginator,对大部分用例是适用的。
- page_size:数值,页面大小,默认是全局PAGE_SIZE的值。
- page_query_param:字符串,查询参数的名称,默认是’page’
- page_size_query_param:字符串,请求设置页面大小的参数名称,默认是None,表示客户端可能无法控制请求的页面大小。
- max_page_size:字符串,最大允许请求的页面大小,此属性仅在page_size_query_param也被设置时有效。
- last_page_strings:字符串列表或者元组,默认是(‘last’,)
- template:分页控件使用的模板的名称,可以覆盖或设置为None,默认为”rest_framework/pagination/numbers.html”
然后,你可以使用.pagination_class
属性将新样式应用于视图:
1 2 3 |
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): pagination_class = StandardResultsSetPagination ... |
或者在settings中使用DEFAULT_PAGINATION_CLASS
全局应用样式。例如:
1 2 3 |
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination' } |
二、分页API
上面演示中我们使用了两种分页的API,分别是PageNumberPagination
和LimitOffsetPagination
。
PageNumberPagination
此分页样式在请求查询参数中接受一个页码值。
Request:
1 |
GET https://api.example.org/accounts/?page=4 |
Response:
1 2 3 4 5 6 7 8 9 |
HTTP 200 OK { "count": 1023 "next": "https://api.example.org/accounts/?page=5", "previous": "https://api.example.org/accounts/?page=3", "results": [ … ] } |
可以看出,响应数据发生了变化。多了count字段,表示所有页统计数;next字段表示下一页的链接;previous字段表示上一页的链接;results字段才是真正包含响应数据。这些额外的字段信息,在前端拿到时非常有用,前端也需要分页。
虽然我们定义的默认page_size是12,但是也是支持前端动态指定的page_size的大小,指定page_size后会覆盖默认page_size大小,这一点非常灵活。
1 |
GET https://api.example.org/accounts/?page=4&page_size=8 |
另外,可以看到 Response 响应的结果是固定的,如果我们想改变输出,可以重写 get_paginated_response 方法,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class AccountViewSet(viewsets.ModelViewSet): """ 用于查看和编辑 Account """ queryset = Account.objects.all() serializer_class = AccountSerializer permission_classes = [IsAccountAdminOrReadOnly] def get_paginated_response(self, data): self.request.GET.get('page_size', self.paginator.page_size) res = { 'PageNumber': self.paginator.page.paginator.count, 'Page': self.paginator.page.number, 'PageSize': self.paginator.page_size, 'Results': data} ) return Response(status=200, data=res) |
LimitOffsetPagination
这种分页样式与SQL语句语法近似,客户端包含 “limit” 和 “offset” 查询参数。limit 表示要返回的 item 的最大数量,并且等同于PageNumberPagination样式中的 page_size。offset 指定查询的起始位置与完整的未分类 item 集的关系。
Request:
1 |
GET https://api.example.org/accounts/?limit=100&offset=400 |
Response:
1 2 3 4 5 6 7 8 9 |
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 类包含一些可以被覆盖以修改分页样式的属性。要设置这些属性,应该继承 LimitOffsetPagination 类,然后像上面那样启用你的自定义分页类。
- default_limit:一个数字值,指定客户端在查询参数中未提供的 limit 。默认值与 PAGE_SIZE setting key 相同。
- limit_query_param:一个字符串值,指示 “limit” 查询参数的名称。默认为 ‘limit’。
- offset_query_param:一个字符串值,指示 “offset” 查询参数的名称。默认为 ‘offset’。
- max_limit:一个数字值,表示客户端可以要求的最大允许 limit。默认为 None。
- template:在可浏览 API 中渲染分页控件时使用的模板的名称。可能会被覆盖以修改渲染样式,或设置为 None 以完全禁用 HTML 分页控件。默认为 “rest_framework/pagination/numbers.html”。