文章目录
一、分页(Pagination)
DRF提供了支持自定义的分页功能,可以帮助我们将查询到的结果集分成若干页。并且还提供了前、后一页的链接:
- 将分页链接作为响应内容的一部分提供给客户端。
- 在响应头中包含分页链接,如
Content-Range
或Link
。
分页只有在使用通用视图(Generic views)或视图集时才会自动执行。如果使用常规的APIView
,则需要我们自己手动调用分页API,确保返回一个分页后的响应。至于如何调用,会在后面讲解。
1.1 内置分页样式
1.1.1 PageNumberPagination
这种分页样式在请求查询参数中接受单个页码(page
):
GET https://api.example.org/accounts/?page=4
它的响应如下,next
表示下一页的链接,previous
表示上一页:
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": [
…
]
}
PageNumberPagination
类包含许多属性,可以重写这些属性以修改分页样式:
page_size
:用于设置每页的大小。page_query_param
:用于设置页码的参数名称,是一个字符串。page_size_query_param
:用于设置一个参数名称,该参数就是用来让客户端在每次请求中,设置分页大小的;默认值为None
,表示不允许客户端设置分页的大小。max_page_size
:用于设置允许请求的最大页面大小。只有在设置了page_size_query_param
时才有效。
1.1.2 LimitOffsetPagination
这种分页样式在客户端请求中包含了一个limit
和一个offset
查询参数:
GET https://api.example.org/accounts/?limit=100&offset=400
-
limit
表示要返回的最大条目数,与其他样式中的page_size
相等。 -
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
类的属性:
page_size
:用于设置每页的大小。但设置该属性后,limit
查询参数将是可选的,并且可能被客户端省略。default_limit
:用于设置limit
的默认值,如果客户端在查询参数中没有提供limit
值,则默认使用该值。limit_query_param
:用于设置limit
参数的参数名称,默认为limit
。offset_query_param
:用于设置offset
参数的参数名称,默认为offset
。max_limit
:用于设置允许客户端请求的最大limit
值。默认为None
。
1.1.3 CursorPagination
这种分页样式不同于上面两种,它提供了一个不透明的游标(cursor
)。通过游标的前后移动来实现分页,但是不支持跳转到任意位置(因为页码是加密的)。并且,它要求查询集必须具有唯一的、不变的顺序。比如以记录的创建时间作为排序依据就是一个很好的选择,它能保证顺序是唯一的。
它的请求格式如下:
GET https://api.example.org/accounts/?cursor=cD0xMg%3D%3D
响应如下,只能访问响应中的前、后一页,无法随意跳转:
HTTP 200 OK
{
"next": "https://api.example.org/accounts/?cursor=cD0xFA%3D%3D",
"previous": "https://api.example.org/accounts/?cursor=cj0xJn9aT%3D",
"results": [
…
]
}
虽然CursorPagination
使用更加复杂,要求也更多。但它有以下的优势:
- 提供一致的分页结果。如果使用得当,
CursorPagination
可以确保客户端不会看到相同的项两次,即使在分页过程中其他客户端插入了新项。 - 支持非常大的数据集。前面两种分页样式在随着数据量的增大效率会逐渐变低,甚至没法使用。而
CursorPagination
不受数据量的影响。
CursorPagination
类的属性:
page_size
:与上面两种分页的page_size
是一样的。cursor_query_param
:用来设置cursor
的参数名称,默认为cursor
。ordering
:接受一个字符串或字符串构成的列表。用于设置排序依据。默认为-created
,即记录创建时间的倒序。
1.2 设置分页样式
-
全局设置:
在项目配置文件中设置
REST_FRAMEWORK = { # 设置分页样式,DRF自带的或者自定义的 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', # 设置每页的大小 'PAGE_SIZE': 100 }
注意:分页样式与每页大小必须同时设置,如果没有设置,则两项的默认值都为
None
。 -
局部设置:
在视图中使用
pagination_class
属性指定分页样式,但通常只在继承了GenericAPIView
的视图才会生效。
1.3 修改分页样式
如果想要基于某一个内置分页样式进行修改定制,则可以通过继承重写的方法,很轻松的完成修改:
class LargeResultsSetPagination(PageNumberPagination):
page_size = 1000
page_size_query_param = 'page_size'
max_page_size = 10000
记得在设置分页时,设置成我们修改定制后的分页样式。
1.4 APIView子类视图调用分页
之前说过,只有Generic views
的子类才会自动调用分页(配置了分页的前提下),如果不是,则需要我们手动调用:
class MyPageNumberPagination(PageNumberPagination):
page_size = 10
class BookView(APIView):
def get(self, request, *args, **kwargs):
book_list = BookModel.objects.all()
# 实例化得到一个分页器对象
page_cursor = MyPageNumberPagination()
# 获取分页后的,因该传递给前端的查询集
book_list = page_cursor.paginate_queryset(
book_list, request, view=self)
# 序列化
book_ser = BookSerializer(book_list, many=True)
# 添加前、后一页的链接等一些额外的信息
res = page_cursor.get_paginated_response(
book_ser.data) # 返回值是Response实例
return res
二、自动生成API文档
API文档可以看作是后端各个API的说明书,常用于帮助项目内成员协作、测试,或提供给用户参考使用。下图就是一个在线文档的图示:
2.1 安装与设置
-
安装:
pip install -U drf-yasg
-
项目配置文件:
INSTALLED_APPS = [ ... 'django.contrib.staticfiles', # 需要服务于swagger ui的css/js文件 'drf_yasg' ]
-
路由文件:
... from rest_framework import permissions from drf_yasg.views import get_schema_view from drf_yasg import openapi ... schema_view = get_schema_view( openapi.Info( title="Snippets API", default_version='v1', description="Test description", terms_of_service="https://www.google.com/policies/terms/", contact=openapi.Contact(email="contact@snippets.local"), license=openapi.License(name="BSD License"), ), public=True, permission_classes=(permissions.AllowAny,), ) urlpatterns = [ url(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), url(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), url(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), ... ]
这会暴露出4个端点:
- API规范的JSON视图:
/swagger.json
- API规范的YAML视图:
/swagger.yaml
- API规范的swagger ui视图:
/swagger/
- API规范的ReDoc ui视图:
/redoc/
- API规范的JSON视图:
2.2 简单配置
get_schema_view
参数:
info
:用来配置api文档的一些基本信息,上述例子中的openapi.Info()
便是,它的参数如下:public
:如果为False,则只包含当前用户可以访问的端点。permission_classes
:模式视图(即API文档视图)本身的权限类。
更加详细的用法请参考官方文档:传送门