67. drf之排序_过滤_分页
1. 排序
1.1 前提
drf排序、过滤、分页只针对查询所有
1.2 drf排序介绍
[1] 概念
DRF 排序存在两种实现方案:内置 OrderingFilter 过滤器、重写 get_queryset 自定义排序。
1. OrderingFilter:标准实现,接收前端 ordering 查询参数,经过白名单校验,在数据库 ORM 层执行 order_by (),不在 Python 内存完成排序;适合常规数据库字段排序。
只有继承 GenericAPIView 的子类才能使用 OrderingFilter 过滤器。
使用OrderingFilter的前提:视图必须继承 GenericAPIView 子类。ModelViewSet、ListAPIView 均间接继承 GenericAPIView,可以直接使用;原生 APIView 没有 filter_queryset 方法,配置 filter_backends 不会自动运行排序逻辑,如需使用必须手动调用 filter_queryset。
2. 重写 get_queryset:手动解析请求参数,编写 ORM 排序逻辑;用于虚拟字段、计算字段、特殊业务规则,内置过滤器无法覆盖的场景。
OrderingFilter运行步骤:前端传递 ordering 查询参数 → 后端白名单校验过滤非法字段 → 转换为 ORM order_by () 执行数据库排序。
[2] OrderingFilter核心配置项
| 配置项 | 作用 |
|---|---|
filter_backends |
过滤器列表,加入 视图类中固定写法:filter_backends = [OrderingFilter] |
ordering_fields |
排序字段白名单,只允许列表内模型数据库字段;外部传入不在白名单的字段直接丢弃;不识别序列化器别名;生产禁止 视图类中需要排序的字段:ordering_fields = ["id", "price"] |
ordering |
默认排序,前端不传ordering时生效;前端传参则覆盖该值 |
[3] 前端传参规则(查询参数名固定:ordering)
1. 字段名 → 升序:?ordering=price
2. 字段前加- → 降序:?ordering=-price
3. 逗号分隔 → 多字段排序:?ordering=-create_time,id
[4] OrderingFilter配置方式
1. 局部配置:写在视图类,仅当前视图生效
2. 全局配置:写在项目的settings.py,全部视图默认生效;视图内部可以重写filter_backends实现局部优先
[5] 约束与适用边界
1. OrderingFilter 仅支持模型真实数据库字段,序列化虚拟字段、计算字段无法直接使用。
2. 遇到内置过滤器无法实现的排序需求,需要采用重写 get_queryset 自定义排序方案。
3. 必须显式配置 ordering_fields 白名单;不配置白名单,前端排序参数直接失效,不能省略该配置。
4. 排序字段只能填写模型数据库字段,序列化器重命名后的别名不能直接用于排序。
5. 大数据场景排序务必配合分页,避免数据库全表排序引发性能问题。
6. 生产环境禁止 ordering_fields="_ _all_ _",防止开放全部字段带来的安全与性能风险。
[6] 使用步骤
(1) 导入模块
(2) 配置
全局配置
REST_FRAMEWORK = {
"DEFAULT_FILTER_BACKENDS": [
"rest_framework.filters.OrderingFilter",
]
}
局部配置:在视图类中
class BookListView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [OrderingFilter] # 使用过滤器
ordering_fields = ["id", "price"] # 第一优先级按 price 升序;当 price 字段值相同的时候,再使用第二优先级id 降序;
1.3 代码准备
app01的models.py
from django.db import models
# Create your models here.
# 1.用户表,用来写登录接口
class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
age = models.IntegerField()
role = models.IntegerField(choices=((1, '普通用户'), (2, '纯路人'), (3, 'vip')))
# 2.用户token表,记录用户的登录情况
class UserToken(models.Model):
# 字符总数:36 个字符(32 位十六进制 + 4 个-分隔符)
token = models.CharField(max_length=64)
user = models.OneToOneField(to=User, on_delete=models.CASCADE)
# 3.图书表
class Book(models.Model):
name = models.CharField(max_length=32)
publish = models.CharField(max_length=32)
price = models.IntegerField()
序列化组件app01的serializer.py
from .models import Book
from rest_framework import serializers
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
app01的views.py
from .serializer import BookSerializer
from .models import Book
from rest_framework.generics import ListAPIView
# 查询所有
class BookView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
app01的urls.py
from django.urls import path
from .views import BookView
urlpatterns = [
path('books/', BookView.as_view()),
]
项目的urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/app01/', include('app01.urls')),
]
查询所有图书,默认以id进行排序

1.4 使用 OrderingFilter 过滤器
[1] 数据准备

[2] 对查询所有图书按价格升序
app01的views.py
from .serializer import BookSerializer
from .models import Book
from rest_framework.generics import ListAPIView
from rest_framework.filters import OrderingFilter
# 查询所有
class BookView(ListAPIView):
filter_backends = [OrderingFilter]
ordering_fields = ['price']
queryset = Book.objects.all()
serializer_class = BookSerializer

[3] 按价格降序
app01的views.py与[2]保持不变

[4] 字段组合排序
先按price升序,如果price一样,再按id降序
app01的views.py
class BookView(ListAPIView):
filter_backends = [OrderingFilter]
ordering_fields = ['price', 'id']
queryset = Book.objects.all()
serializer_class = BookSerializer

2. 过滤
2.1 drf过滤介绍
[1] 概念
DRF 过滤组件读取 URL 查询参数,对 ORM 查询集附加筛选条件,实现接口返回结果的动态过滤。
过滤逻辑仅对 list 列表接口(即查询所有)生效;retrieve、create、update、destroy 不会触发过滤。
共三类常用过滤后端:
1. DjangoFilterBackend:依赖 django‑filter 库,支持等值、区间、模糊等各类数据库条件筛选。 第三方模块
2. SearchFilter:DRF 内置组件,用于文本关键词检索。
3. OrderingFilter:DRF 内置组件,用于查询结果动态排序。
[2] 原理
filter_queryset 为过滤统一入口。
原始查询集,按照 filter_backends 列表的顺序,依次交给每一个过滤后端处理。后端解析请求参数,叠加 ORM 查询条件;处理完成后的查询集,继续流转到分页、序列化环节。
配置优先级规则:
1. DEFAULT_FILTER_BACKENDS,设置项目全局默认过滤后端。
2. 视图内 filter_backends 属性,直接覆盖全局配置,不会自动合并。
[3] 过滤组件全局配置
环境准备: 运行安装命令 pip install django-filter
settings.py 全局注册与配置
INSTALLED_APPS = [
...
'django_filters'
]
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter'
]
}
2.2 SearchFilter使用
[1] 概念
用途:文本关键词搜索。
固定读取 url 参数 search,与search_fields中字段的值匹配。
search_fields 多字段含义:
search_fields = ["title", "author"]
代表同时在 title、author 两个字段做关键词检索,前端接口仍然只用一个 search 参数,不需要传多个参数。
请求示例:
GET /books/?search=信息论
只要标题或者作者任意一个字段包含传入的关键词,就可以匹配成功。
查询参数名固定为 search,不会因为 search_fields 有多个字段就新增请求参数。多个字段是后端内部 OR 逻辑合并,前端只传一次 search 值。
要点:
1. search 只接收单个字符串,无法分别给 title、author 传不同关键词。
如果业务需要:单独对标题搜 A,对作者搜 B,SearchFilter 做不到,要放到 DjangoFilterBackend 自定义 filterset 实现。
2. search_fields 写模型字段名,不要写序列化器字段名。
3. 不传 search 参数时,SearchFilter 不会追加任何条件,不影响接口。
4. SearchFilter 默认是模糊搜索,不是精确匹配。
[2] 代码
需求:过滤图书名字中含有“信”字的图书
app01的views.py
from .serializer import BookSerializer
from .models import Book
from rest_framework.generics import ListAPIView
from rest_framework.filters import SearchFilter
# 查询所有
class BookView(ListAPIView):
filter_backends = [SearchFilter] # 使用搜索
search_fields = ['name'] # 设置搜索的字段
queryset = Book.objects.all()
serializer_class = BookSerializer

2.3 第三方模块DjangoFilterBackend使用
[1] 概念
用途:数据库条件过滤。
使用需要先安装 pip install django-filter
[2] 用法一:filterset_fields,仅支持等值精准匹配
在视图类配置 filterset_fields,填写字段,仅可做完全相等的精准匹配。
(1) 需求:精准匹配一个字段,“南洋理工出版社”,文字不可缺少
app01的views.py
from .serializer import BookSerializer
from .models import Book
from rest_framework.generics import ListAPIView
from django_filters.rest_framework.backends import DjangoFilterBackend
# 查询所有
class BookView(ListAPIView):
filter_backends = [DjangoFilterBackend] # 使用第三方模块
filterset_fields = ['publish'] # 设置需要匹配的字段
queryset = Book.objects.all()
serializer_class = BookSerializer
精准匹配“南洋理工出版社”

模糊匹配失败

(2) 需求:精准匹配两个字段,名称和出版社
app01的views.py
class BookView(ListAPIView):
filter_backends = [DjangoFilterBackend] # 使用第三方模块
filterset_fields = ['name', 'publish'] # 设置需要匹配的字段
queryset = Book.objects.all()
serializer_class = BookSerializer
精准匹配成功

模糊匹配失败

[3] 用法二:自定义过滤类,实现区间、模糊过滤
当需要大于、小于、包含匹配等复杂条件时,需要自定义过滤类。
需求:匹配name中带有“信”字,并且price大于30

自定义过滤类需要放在单独的文件中,命名为app01的filters.py
from rest_framework.filters import BaseFilterBackend
# http://127.0.0.1:8000/api/v1/app01/books/?name=信&price=30
class BookFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
"""
:param request: HTTP 请求对象,从中获取 URL 查询参数,也就是 url 问号后面携带的参数。
:param queryset: 视图传入的原始数据集,数据库查询的初始结果集。filter 操作不会修改原对象,每次 filter 会生成新查询集。
:param view: 当前调用该过滤器的视图类实例,可以读取视图里面定义的属性。
:return:
"""
# 取出过滤条件
name1 = request.query_params.get('name', None)
price1 = request.query_params.get('price', None)
if name1:
queryset = queryset.filter(name__icontains=name1) # 模糊匹配,字段name包含前端传来的值name1
if price1:
queryset = queryset.filter(price__gt=price1) # 字段price大于前端传来的值price1
return queryset
建议写成多个if的形式,不要写成if name1 & price1的形式,可能会触发bug
app01的views.py
from .serializer import BookSerializer
from .models import Book
from rest_framework.generics import ListAPIView
from .filters import BookFilter# 查询所有
class BookView(ListAPIView):
filter_backends = [BookFilter] # 使用自定义的过滤类,类中已经设置需要匹配的字段,这里无需额外设置
queryset = Book.objects.all()
serializer_class = BookSerializer
| 类型 | 父类 | 能否放在 filter_backends | 使用方式 |
|---|---|---|---|
| 自定义过滤器后端 | BaseFilterBackend | 可以 | 直接写进 filter_backends 列表 |
| SearchFilter / OrderingFilter | BaseFilterBackend | 可以 | 直接写进 filter_backends 列表 |
| DjangoFilterBackend | BaseFilterBackend | 可以 |
作为运行,配合 filterset_class filter_backends = [DjangoFilterBackend]
filterset_class = 自定义过滤类 |
| django‑filter.FilterSet 子类 | object | 不可以 | 视图属性 filterset_class 引用 |
业务逻辑:
1. 从 request.query_params 读取 url 上的 name、price 两个查询参数,取不到时赋值 None。
2. 如果 url 携带 name 参数:执行 name__icontains 过滤,做不区分大小写的模糊包含匹配。
3. 如果 url 携带 price 参数:执行 price__gt 过滤,匹配价格大于传入数值的数据。
4. 返回经过叠加过滤之后的 queryset。
可以实现的接口效果:
| 请求 URL | 执行效果 |
|---|---|
| /books/ | 不传参数,返回全部书本数据 |
| /books/?name = 信 | 查询书本名称包含信,大小写不敏感的全部记录 |
| /books/?price=30 | 查询价格大于 30 的全部书本记录 |
| /books/?name = 信 & price=30 | 同时生效:名称模糊匹配信,并且价格大于 30,两个条件为并且关系 |
关键点:
1. price 从 url 取出来是字符串类型,DRF 内部 filter 会自动完成类型转换;传入非数字字符串,会直接抛出数据库异常。
2. 多个 if 独立判断,参数可以单独使用,也可以组合使用;没有参数时直接返回原始 queryset,不会过滤。
不传参数,返回全部书本数据

查询书本名称包含信,大小写不敏感的全部记录

查询价格大于 30 的全部书本记录

名称模糊匹配信,并且价格大于 30,两个条件为并且关系

2.4 过滤和排序组合使用
filter_backends 列表填写多个后端,按列表顺序依次运行过滤逻辑。
自定义过滤器app01的filters.py
from rest_framework.filters import BaseFilterBackend
# http://127.0.0.1:8000/api/v1/app01/books/?name=信&price=60
class BookFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
"""
:param request: 总数据
:param queryset: 当次请求对象
:param view: 视图类对象
:return:
"""
# 取出过滤条件
name1 = request.query_params.get('name', None)
price1 = request.query_params.get('price', None)
if name1:
queryset = queryset.filter(name__icontains=name1) # 模糊匹配,字段name包含前端传来的值name1
if price1:
queryset = queryset.filter(price__gt=price1) # 字段price大于前端传来的值price1
return queryset
app01的views.py
from .serializer import BookSerializer
from .models import Book
from rest_framework.generics import ListAPIView
from .filters import BookFilter
from rest_framework.filters import OrderingFilter, SearchFilter
# 查询所有
class BookView(ListAPIView):
filter_backends = [BookFilter, SearchFilter, OrderingFilter] # 使用自定义的过滤类,类中已经设置需要匹配的字段,这里无需额外设置
search_fields = ['name', 'publish']
ordering_fields = ['price', 'id']
queryset = Book.objects.all()
serializer_class = BookSerializer
概念说明:
自定义 BookFilter 实现 name 模糊匹配、price 大于条件过滤。
SearchFilter 依靠 search_fields 配置,单个 search 查询参数,对配置内全部字段执行或逻辑模糊查询。
OrderingFilter 依靠 ordering_fields 配置,支持逗号分隔多字段排序,可同时使用配置列表内全部字段,负号代表降序。
filter_backends 执行顺序:BookFilter → SearchFilter → OrderingFilter。
运行逻辑为先过滤数据集,再做关键词检索,最后执行排序。
接口:
GET /books/?name = 信 & price=20&search = 麻省理工出版社 & ordering=price,-id
| 参数 | 作用 |
|---|---|
| name = "信" | 自定义过滤器,name 字段大小写不敏感模糊包含"信" |
| price=20 | 自定义过滤器,筛选价格大于20 |
| search = 麻省理工出版社 | SearchFilter,同时检索 name、publish 字段,命中任意一个即匹配 |
| ordering=-price,id | OrderingFilter,优先 price升序,价格相同则id降序,两个排序字段全部启用 |
运行步骤:
1. 获取 Book 全部原始查询集。
2. BookFilter 执行过滤,保留 name 包含"信"、price 大于20的数据子集。
3. SearchFilter 在上一步子集内筛选,匹配 name 或 publish 包含麻省理工出版社的记录。
4. OrderingFilter 执行多字段排序。
5. BookSerializer 序列化输出结果。


2.5 练习
需求:继承APIView实现过滤
方式一:
app01的views.py
from rest_framework.views import APIView
class BookViewSet(APIView):
def get(self, request, *args, **kwargs):
obj_list = Book.objects.all()
# 取出需要过滤的字段
name = request.query_params.get('name')
price = request.query_params.get('price')
if name:
obj_list = obj_list.filter(name=name)
if price:
obj_list = obj_list.filter(price=price)
serializer = BookSerializer(obj_list, many=True)
return Response(serializer.data)
基于 APIView 实现自定义查询接口,接收 GET 请求,完成图书列表查询,同时支持 name、price 两个 URL 查询参数做等值过滤,返回序列化后的图书 JSON 列表数据。
运行步骤:
1. 接收 HTTP GET 请求进入 get 方法。
2. 查询全部 Book 表数据作为初始查询集。
3. 从 url 查询参数中提取 name 与 price。
4. 参数存在时,对查询集执行对应字段等值过滤。
5. 使用 BookSerializer 对结果做多对象序列化。
6. 将序列化数据通过 Response 返回。
接口示例
示例 1:获取全部图书
GET /xxx/books
示例 2:按图书名称精确匹配过滤
GET /xxx/books?name = 信息论
示例 3:按价格精确匹配过滤
GET /xxx/books?price=39
示例 4:两个参数同时生效,相当于 AND 条件
GET /xxx/books?name = 信息论 & price=39
关键点:
1. 仅支持 GET 请求,没有post、put、delete,不具备增删改。
2. 过滤为完全等值匹配,不支持模糊查询、大于小于区间筛选。
方式二:
过滤组件app01的filters.py
from rest_framework.filters import BaseFilterBackend
# http://127.0.0.1:8000/api/v1/app01/books/?name=信&price=60
class BookFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
"""
:param request: 总数据
:param queryset: 当次请求对象
:param view: 视图类对象
:return:
"""
# 取出过滤条件
name1 = request.query_params.get('name', None)
price1 = request.query_params.get('price', None)
if name1:
queryset = queryset.filter(name__icontains=name1) # 模糊匹配,字段name包含前端传来的值name1
if price1:
queryset = queryset.filter(price__gt=price1) # 字段price大于前端传来的值price1
return queryset
app01的views.py
from rest_framework.views import APIView
from .filters import BookFilter
class BookViewSet(APIView):
def get(self, request, *args, **kwargs):
obj_list = Book.objects.all()
# 取出需要过滤的字段
obj_list = BookFilter.filter_queryset(request, obj_list, self)
serializer = BookSerializer(obj_list, many=True)
return Response(serializer.data)
自定义 BaseFilterBackend 过滤器类,在 APIView 视图中手动调用过滤器方法,实现 GET 请求下对图书列表的过滤。name 运行不区分大小写模糊匹配,price运行大于数值过滤,返回过滤完成后的序列化图书列表。
运行步骤:
1. 接收 GET 请求进入 get 方法。
2. 获取 Book 表全部数据作为原始查询集。
3. 手动调用 BookFilter 的 filter_queryset 静态方式,传入 request、查询集、视图实例。
4. 读取 url 查询参数 name1、price1。
5. name1 存在:使用 name__icontains 做不区分大小写模糊检索。
6. price1 存在:使用 price__gt 做价格大于传入值的过滤。
7. 返回处理后的查询集交给序列化器输出 JSON 数组。
接口示例
示例 1:全部数据
GET /books/
示例 2:名称模糊匹配,不区分大小写
GET /books/?name1 = 信
匹配:信息论、通信原理等包含 “信” 的记录。
示例 3:价格大于指定数值
GET /books/?price1=30
返回所有 price>30 的图书。
示例 4:两个参数组合,逻辑 AND
GET /books/?name1 = 三 & price1=30
返回名称含 “三” 并且价格大于 30 的数据。
关键特点
1. BookFilter 继承 BaseFilterBackend,是 DRF 标准过滤器基类,但此处没有使用视图 filter_backends 配置,属于手动调用过滤器函数,不是 DRF 原生自动调用机制。
2. 过滤条件逻辑为 AND,多参数同时提供时条件叠加。
和方式一的区别
1. name:等值匹配 → icontains 模糊不区分大小写。
2. price:等于匹配 → gt 大于过滤。
3. 过滤逻辑抽成 BaseFilterBackend 过滤器类,但手动调用,没有利用 GenericAPIView 的过滤器自动执行机制。
3. 分页
3.1 概念
[1] 基础概念
drf分页只针对于查询所有
手机app端:下拉加载下一页
web端:点击加载下一页
[2] 三种分页方式
DRF 分页提供三种内置分页类,分别为普通分页、偏移分页、游标分页,支持全局配置与视图局部配置两种配置方式。
| 分页类 | 类路径 | 分页逻辑 | 适用场景 | |
|---|---|---|---|---|
| PageNumberPagination | 普通分页 | rest_framework.pagination.PageNumberPagination | 传递 page 参数,按页码分页 | 简单列表,支持跳转到任意页 |
| LimitOffsetPagination | 偏移分页 | rest_framework.pagination.LimitOffsetPagination | 传递 limit、offset 参数,从偏移位置取数据 | 需要做数据偏移,适合前端滚动加载 |
| CursorPagination | 游标分页 | rest_framework.pagination.CursorPagination | 传递 cursor 游标,基于排序字段分页 | 大数据量,不支持跳页,避免分页数据重复丢失 |
[3] 使用步骤
定义分页类,继承三个分页类之一
在分页类中,重写类中的某些函数
在继承GenericAPIView的子类中,配置pagination_class = CommonCursorPagination
3.2 代码示例
[1] 普通分页--自定义
(1) 代码
分页类需要放在单独的文件中,定义为app01的page.py
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
class TurnPage(PageNumberPagination):
page_size = 2 # 每页显示2条
page_query_param = 'page' # 页码参数名,值为page时,接口为/books/?page=3 值为p时,接口为/books/?p=3,都是访问第3页
page_size_query_param = 'size' # 值定义为size时,/books/?page=6&size=10,查询的第6页并且将原来默认每页显示2条动态调整为10条,所有页数都是10条,不止第6页
max_page_size = 5 # 通过以上size指定时,最多只显示5条
page_size:默认每页条数
page_size_query_param:允许前端传参动态修改每页数量的参数名
max_page_size:前端可请求的最大单页条数,防止一次性请求大量数据
page_query_param:页码请求参数名
app01的views.py
from .serializer import BookSerializer
from .models import Book
from rest_framework.generics import ListAPIView
from .page import TurnPage
# 查询所有
class BookView(ListAPIView):
pagination_class = TurnPage
queryset = Book.objects.all()
serializer_class = BookSerializer
(2) 接口示例
http://127.0.0.1:8000/api/v1/app01/books/?page=1 查询第1页,每页返回默认2条数据
http://127.0.0.1:8000/api/v1/app01/books/?page=2 查询第2页,每页返回默认2条数据
http://127.0.0.1:8000/api/v1/app01/books/?page=2&size=4 查询第2页,返回4条数据,查询所有的页数都将返回4条,不止第2页
http://127.0.0.1:8000/api/v1/app01/books/?page=1&size=60000 查询第1页,按max_page_size最多只显示5条
(3) 接口测试
查询所有,总共5条,每页显示2条,下一页为第2页

查询第2页,下一页为第3页

查询第2页,每页条数动态修改为3页
动态修改后第1页显示的条数为1、2、3,因此第2页只能显示剩下的4、5

当第2页超过max_page_size时,第1页已经显示max_page_size = 5的5条,第2页已经查询不到数据

当第1页超过max_page_size时,第1页显示max_page_size = 5的5条,获取到了所有数据

[2] 偏移分页
app01的views.py无需改变,app01的page.py如下
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
class TurnPage(LimitOffsetPagination):
# 参数在源码中
default_limit = 2 # 每页默认显示2条
limit_query_param = 'limit'
offset_query_param = 'offset'
max_limit = 5 # 每页最多显示5条
自定义类核心参数解释
default_limit:默认单页返回条数,等价全局 PAGE_SIZE。
limit_query_param:前端控制每页条数参数名,默认 limit。
offset_query_param:前端控制偏移量参数名,默认 offset。 偏移量从0开始,根据偏移量和limit计算页码
max_limit:前端允许设置的最大 limit,限制单次返回数据量。
查询所有,每页最多按limit显示2条

偏移量offset=2,从计数3开始,按limit每页显示2条

偏移量offset=4,从计数5开始,按limit每页显示2条,这里已经显示最后一条

偏移量offset=2,从计数3开始,按limit每页显示3条

[3] 游标分页
(1) 概念
先排序,后分页,只能前一页和后一页
必须提供排序字段,无总 count 返回不支持指定页码跳转。
(2) 代码
app01的page.py
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
class TurnPage(CursorPagination):
# 参数在源码中
page_size = 2 # 每页默认显示2条
cursor_query_param = 'cursor'
ordering = 'id' # 分页的依据
(3) 参数解释
page_size:默认每页条数。
cursor_query_param:前端传递游标字符串的参数名,默认 cursor。
ordering:必填,数据库排序字段,优先使用唯一主键,字段不唯一会造成数据错乱。
page_size_query_param:允许前端动态修改每页条数。
max_page_size:前端可设置最大每页条数上限。
(4) 接口测试
查询所有,按page_size每页默认显示2条

根据生成的cursor参数进行上一页与下一页的跳转

优点:大数据量翻页性能优秀;新增删除数据不会出现重复漏数据。
缺点:没有总条数 count;不能跳页;排序字段尽量使用唯一主键,否则会错乱。

浙公网安备 33010602011771号