15.1 分页
分页模式
rest framework中提供了三种分页模式:
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
全局配置
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 100
}
局部配置
15.1.2 drf局部分页设置
在视图中指明自定义的分页类
# HeroListCreateAPIView/?page=2&size=2 查询第2页,每页2条的英雄信息
class HeroListCreateAPIView(ListCreateAPIView):
queryset = Hero.objects.all() # 查询集
serializer_class = HeroModelSerializer # 自己定义的序列化器
# 没有指明分页类,会按照全局分页
pagination_class = Pagination # 使用自定义的分页类
15.1.3 drf自定义分页类对象重写分页属性
自定义分页类,实现属性的重写
# 只有某些视图,需要分页, 可以自定义分页类
class Pagination(PageNumberPagination):
page_size = 1 # 每页数量
max_page_size = 3 # 每页最大的数量 以访特殊情况写不写都行
page_size_query_param = 'size' # 每页数量的参数名 供前端使用的
page_query_param = 'page' # 页码的参数名2
我们还可以在视图类中进行这样的局部设置
class PublisherViewSet(ModelViewSet):
queryset = models.Publisher.objects.all()
serializer_class = PublisherModelSerializer
pagination_class = PageNumberPagination # 注意不是列表(只能有一个分页模式)
DRF内置分页器
1、PageNumberPagination
按页码数分页,第n页,每页显示m条数据,例如:http://127.0.0.1:8000/api/article/?page=2&size=1
分页器
# 重写
class MyPageNumber(PageNumberPagination):
page_size = 2 # 每页显示多少条
page_size_query_param = 'size' # URL中每页显示条数的参数
page_query_param = 'page' # URL中页码的参数
max_page_size = None # 最大页码数限制
# 如果我要的数据是第一页显示10条: http://127.0.0.1:8000/books/?size=10&page=1
# 如果我要的是第二页显示5条: http://127.0.0.1:8000/books/?size=5&page=2
# max_page_size = 8 :控制最大显示多少条如果我想第一页显示10000条,这种不合理,通过这个参数控制,最大显示8条
视图
class ArticleList(APIView):
def get(self, request, *args, **kwargs):
res = {"code": 0}
article_list = models.Article.objects.all().order_by("id")
# 分页
page_obj = MyPageNumber()
page_article = page_obj.paginate_queryset(queryset=article_list, request=request, view=self)
ser_obj = ArticleSerializer(page_article, many=True)
res["data"] = ser_obj.data
return Response(res)
返回带页码链接的响应
class ArticleList(APIView):
def get(self, request, *args, **kwargs):
res = {"code": 0}
article_list = models.Article.objects.all().order_by("id")
# 分页
page_obj = MyPageNumber()
page_article = page_obj.paginate_queryset(queryset=article_list, request=request, view=self)
ser_obj = ArticleSerializer(page_article, many=True)
res["data"] = ser_obj.data
return page_obj.get_paginated_response(res)
2、LimitOffsetPagination
分页,在n位置,向后查看m条数据,例如:http://127.0.0.1:8000/api/article/?offset=2&limit=2
分页器
# offset分页
class MyLimitOffset(LimitOffsetPagination):
default_limit = 5 # 默认偏移的条数 5
limit_query_param = 'limit' # 偏移的条数
offset_query_param = 'offset' # 从哪开始偏移
max_limit = 999 # 偏移的最大条数
-http://127.0.0.1:8000/books/ 结果是:从1到5
-http://127.0.0.1:8000/books/?limit=7 结果是:从1到7
-http://127.0.0.1:8000/books/?limit=2&offset=6 结果是:从7到8,两条
-http://127.0.0.1:8000/books/?offset=6 结果是:从7到11,5条
视图
class ArticleList(APIView):
def get(self, request, *args, **kwargs):
res = {"code": 0}
article_list = models.Article.objects.all().order_by("id")
# 分页
page_obj = MyLimitOffset()
page_article = page_obj.paginate_queryset(queryset=article_list, request=request, view=self)
ser_obj = ArticleSerializer(page_article, many=True)
res["data"] = ser_obj.data
return page_obj.get_paginated_response(res)
3、CursorPagination
加密分页,把上一页和下一页的id值记住
分页器
# 加密分页
class MyCursorPagination(CursorPagination):
cursor_query_param = 'cursor'
page_size = 1 # 每页显示的条数
ordering = '-id' # 按谁排序
视图
class ArticleList(APIView):
def get(self, request, *args, **kwargs):
res = {"code": 0}
article_list = models.Article.objects.all().order_by("id")
# 分页
page_obj = MyCursorPagination()
page_article = page_obj.paginate_queryset(queryset=article_list, request=request, view=self)
ser_obj = ArticleSerializer(page_article, many=True)
res["data"] = ser_obj.data
# return Response(res)
return page_obj.get_paginated_response(res)
15.2 过滤
15.2.1 django-filter的精准过滤
-
安装插件
该django-filter库包含一个DjangoFilterBackend
类,该类支持针对REST框架的高度可自定义的字段筛选。
要使用
DjangoFilterBackend
,请先安装django-filter
。
pip install django-filter
-
注册APP
添加
'django_filters'
到Django的INSTALLED_APPS
:
INSTALLED_APPS = [
...
'django_filters',
...
]
-
配置过滤引擎
将过滤器后端添加到全局设置中:
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}
或将过滤器后端添加到单个View
或ViewSet
。
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.generics import ListAPIView
class GoodsListAPIView(ListAPIView):
...
filter_backends = (DjangoFilterBackend,)
如果只需要简单的基于模型类字段的等式过滤,则可以filterset_fields
在视图或视图集上设置一个属性,列出要过滤的字段集。
class GoodsListAPIView(ListAPIView):
queryset = GoodsModel.objects.all()
serializer_class = GoodsModelSerializer
# filter_backends = (DjangoFilterBackend, ) # 如果全局设置过,局部不需要设置
filter_fields = ('price', 'name')
FilterSet
将自动为给定的字段创建一个类,并允许您发出如下请求:
http://127.0.0.1:8000/api/goods/?price=5&name=西瓜
15.2.2 django-filter的模糊过滤
自定义过滤器,实现高级过滤
class GoodsFilter(django_filters.rest_framework.FilterSet):
"""商品的过滤类"""
min_price = django_filters.NumberFilter(field_name="price",lookup_expr="gte")
# field_name 表示要过滤字段;lookup_expr 表示 过滤时要进行的操作,gte 表示 大于等于
max_price = django_filters.NumberFilter(field_name="price", lookup_expr="lte") # lte 小于等于
name = django_filters.CharFilter(field_name="name", lookup_expr="icontains") # icontains 表示 包含(忽略大小写)
class Meta:
model = GoodsModel # 关联的表
fields = ["min_price", "max_price", "name"] # 过滤的字段
class GoodsListAPIView(ListAPIView):
queryset = GoodsModel.objects.all()
serializer_class = GoodsModelSerializer
filterset_class = GoodsFilter # 指明过滤器类
FilterSet
将自动为给定的字段创建一个类,并允许您发出如下请求:
http://127.0.0.1:8000/api/goods/?max_price=50&name=瓜
15.2.3 rest_framework的SearchFilter
该搜索引擎依赖于
rest_framework
, 不需要安装额外的插件
-
配置搜索引擎
将过滤器后端添加到全局设置中:
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ['rest_framework.filters.SearchFilter']
}
或将过滤器后端添加到单个
View
或ViewSet
。
from rest_framework.filters import SearchFilter
from rest_framework.generics import ListAPIView
class GoodsListAPIView(ListAPIView):
...
filter_backends = [SearchFilter]
-
配置搜索字段
from rest_framework.filters import SearchFilter
from rest_framework.generics import ListAPIView
class GoodsListAPIView(ListAPIView):
...
search_fields = ['name']
这将允许客户端通过执行以下查询来过滤列表中的项目:
http://127.0.0.1:8000/api/goods/?search=西瓜汁
您还可以使用查找API双下划线表示法在ForeignKey或ManyToManyField上执行相关查找:
search_fields = ['name', 'cate__name']
默认情况下,搜索将使用不区分大小写的部分匹配。搜索参数可以包含多个搜索词,应将其用空格或逗号分隔。如果使用多个搜索词,则仅当所有提供的词都匹配时,对象才会在列表中返回。
可以通过在字符前面添加各种字符来限制搜索行为search_fields
。
-
'^'
开始搜索 -
'='
完全匹配 -
'$'
正则表达式搜索
模糊搜索和排序 代码实现:
pip install django-filter
# settings配置 注册一下
INSTALLED_APPS = [
'django_filters',
]
# 序列化器
class ShopSer(serializers.ModelSerializer):
# 如有外键,当声明 可供搜索使用
# kind = serializers.StringRelatedField(read_only=True)
class Meta:
model = Shop
fields = '__all__'
#视图
from rest_framework.generics import ListAPIView
from rest_framework.filters import OrderingFilter, SearchFilter
class ShopFunction(ListAPIView):
queryset = Shop.objects.all()
serializer_class = ShopSer
filter_backends = [OrderingFilter, SearchFilter]
search_fields = ['id', 'name'] # 如有外键kind_id,即为'kind__id'
ordering_fields = ['id']
# 路由 主路由为shop/
from django.urls import path
from shop import views
urlpatterns = [
path('shopfunction/', views.ShopFunction.as_view()),
]
# 前端请求
# http://127.0.0.1:8000/shop/shopfunction/?search=鸡排
let url = 'shop/shopfunction/?search=' + this.name
get(url)
# http://127.0.0.1:8000/shop/shopfunction/?ordering=-id
let url = 'shop/shopfunction/?ordering=-id'
get(url)