Django REST Framework——7. 分页与文档生成

一、分页(Pagination)

DRF提供了支持自定义的分页功能,可以帮助我们将查询到的结果集分成若干页。并且还提供了前、后一页的链接:

  • 将分页链接作为响应内容的一部分提供给客户端。
  • 在响应头中包含分页链接,如Content-RangeLink

分页只有在使用通用视图(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个端点:

    1. API规范的JSON视图:/swagger.json
    2. API规范的YAML视图:/swagger.yaml
    3. API规范的swagger ui视图:/swagger/
    4. API规范的ReDoc ui视图:/redoc/

2.2 简单配置

get_schema_view参数:

  • info:用来配置api文档的一些基本信息,上述例子中的openapi.Info()便是,它的参数如下:
    • title (str) –API文档标题,必须。
    • default_version (str) – API的版本,必须。
    • description (str) – API的描述,支持markdown。
    • terms_of_service (str) – API服务条款,是一个url。
    • contact (Contact) – 联系对象。
    • license (License) – 许可对象。
  • public:如果为False,则只包含当前用户可以访问的端点。
  • permission_classes:模式视图(即API文档视图)本身的权限类。

更加详细的用法请参考官方文档:传送门

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花_城

你的鼓励就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值