django: django rest framework 分页

django rest framework pagination

在drf中对于数据的返回支持多种分页技巧,在官网中主要向我们介绍了PageNumberPaginationLimitOffsetPaginationCursorPagination

本课程的讲解使用示例项目,该项目的目录结构如下所示:
django: django rest framework 分页_第1张图片

目录结构

该目录结构与django原生的目录结构差异较大,其中所有的django应用都在apps目录中,目前拥有assets和rbac两个应用。conf内存放的是urls,py和wsgi.py文件,在settings目录中写入了该项目的配置文件base.py。

对于drf的分页可以采用全局配置对每个视图进行单独配置的方法。

如果采用全局配置需要在配置文件中设置,例如将全局分页设置为PageNumberPagination,需要在base.py中添加如下配置:

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

如果需要对每个视图进行单独配置,需要设置ModelViewSet中的pagination_class值,示例如下:

class MachineRoomViewSet(viewsets.ModelViewSet):
    """
    机房操作视图
    """
    queryset = MachineRoom.objects.all()
    serializer_class = MachineRoomSerializer
    pagination_class = PageNumberPagination

下面分别介绍这三个的使用方法:


PageNumberPagination

此分页样式在请求查询参数中接受单个号码页码。用户可以指定访问的页数,示例如下:

GET http://127.0.0.1:8060/assets/v1/regions/?page=2

返回的内容如下:

HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "results": [
        {
            "id": 3,
            "region_name": "华西",
            "created_time": "2018-06-20T08:52:32.871964Z",
            "modified_time": null
        },
        {
            "id": 4,
            "region_name": "华北",
            "created_time": "2018-06-20T14:47:46.910065Z",
            "modified_time": null
        }
    ],
    "pagination": 4,
    "page_size": 2,
    "page": 2
}

按照页数访问是比较常见的一种做法,所以我们大多数情况使用PageNumberPagination,上述的返回结果集进行了调整,这是继承PageNumberPagination类,对其get_paginated_response函数的返回内容格式进行了再定义。
后续在介绍自定义分页格式时会进行详细介绍。PageNumberPagination的默认返回格式为:

HTTP 200 OK
{
    "count": 1023
    "next": "https://api.example.org/accounts/?page=5",
    "previous": "https://api.example.org/accounts/?page=3",
    "results": [
       …
    ]
}

包含next(下一页)和previous(上一页)两个跳转地址。


LimitOffsetPagination

这种分页样式反映了查找多个数据库记录时使用的语法,客户端包含“limit(限制)”和“offset(偏移量)”查询参数。
该限制表示要返回的项目的最大数量,并且等同于其他样式中的page_size。
偏移量指示查询的起始位置与完整的未分类项目集的关系。

使用这种分页方式的model进行查询的时候需要指定limit(个数)和offset(起始位置)。

GET http://127.0.0.1:8060/assets/v1/regions/?limit=1&offset=2

返回结果如下:

HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "count": 4,
    "next": "http://127.0.0.1:8060/assets/v1/regions/?limit=1&offset=3",
    "previous": "http://127.0.0.1:8060/assets/v1/regions/?limit=1&offset=1",
    "results": [
        {
            "id": 3,
            "region_name": "华西",
            "created_time": "2018-06-20T08:52:32.871964Z",
            "modified_time": null
        }
    ]
}

CursorPagination

基于游标的分页提供了一个不透明的 “游标” 指示器,客户端可以使用该指示器来翻阅结果集。此分页样式仅提供前向和反向控件,并且不允许客户端导航到任意位置。

基于游标的分页需要在结果集中存在唯一的,不变的 item 顺序。这种排序通常可以是记录上的创建时间戳,因为这确保了排序的一致性。

假设我们以创建时间来进行排序,新建时间一般是无法进行修改的。该字段的内容只需要设置一次。但是时间也有可能冲突。为了避免这种重复问题,可以对该条信息的数据抽取出特征值而组合成一个唯一的字符串。例如:假设我们我们对一个云主机设置一个不会冲突的字段:可以使用如下格式“名称-规格-创建时间”,这样的一条信息应该是不会冲突的。

CursorPagination的参数配置如下:

page_size = 指定页面大小的数字值。如果设置,则会覆盖 PAGE_SIZE 设置。默认值与 PAGE_SIZE setting key 相同。
cursor_query_param = 一个字符串值,指定 “游标” 查询参数的名称。默认为 ‘cursor’.
ordering = 这应该是一个字符串或字符串列表,指定将应用基于游标的分页的字段。例如: ordering = ‘slug’。默认为 -created。该值也可以通过在视图上使用 OrderingFilter 来覆盖。
template = 在可浏览 API 中渲染分页控件时使用的模板的名称。可能会被覆盖以修改渲染样式,或设置为 None 以完全禁用 HTML 分页控件。默认为 “rest_framework/pagination/previous_and_next.html”


自定义分页类

除了drf给出的上述三种分页方法,用户可以根据自己的需求进行自定义分页以适应不同业务需求。这个可以继承并拓展drf的分页类。我们编写一个MyFormatResultsSetPagination自定义分页类,该类继承自PageNumberPagination,内容如下:

class MyFormatResultsSetPagination(pagination.PageNumberPagination):

    page_size_query_param = "page_size"
    page_query_param = 'page'
    page_size = 2
    max_page_size = 1000

    """
    自定义分页方法
    """
    def get_paginated_response(self, data):
        """
        设置返回内容格式
        """
        return Response({
            'results': data,
            'pagination': self.page.paginator.count,
            'page_size': self.page.paginator.per_page,
            'page': self.page.start_index() // self.page.paginator.per_page + 1
        })

在get_paginated_response重写了返回格式。

如果要使用自定义分页类,只需要在ModelViewSet中设定pagination_class为自定义分类。示例如下:

class RegionViewSet(viewsets.ModelViewSet):
    """
    区域操作视图
    """
    queryset = Region.objects.all()
    serializer_class = RegionSerializer
    pagination_class = MyFormatResultsSetPagination    # 自定义分页

小结

分页是后端restful接口一个非常常见的需求,django rest framework为我们编写业务简化了很多操作。需要熟练掌握。

你可能感兴趣的:(python,django,实战)