Django分页,过滤:

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']
}

 或将过滤器后端添加到单个ViewViewSet

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']
}

或将过滤器后端添加到单个ViewViewSet

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)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值