• DRF ---- 过滤组件 分页组件 过滤组件插件使用


    DRF过滤组件

    1 源码分析:

    入口: 群查 ListModelMixin 内的 list 但是方法都由 GenericAPIView 提供

        def list(self, request, *args, **kwargs):
            
            # 过滤queryset 对象 得到 queryset 对象 方法都在 GenericApiView 里面
            queryset = self.filter_queryset(self.get_queryset())
            # 分页组件
            page = self.paginate_queryset(queryset)
            
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return self.get_paginated_response(serializer.data)
    
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)
    

    GenericAPIView 找到 filter_queryset

    def filter_queryset(self, queryset):
    	# 从配置文件中拿到 filter_backends 循环 然后调用 犯法 filter_queryset
    	for backend in list(self.filter_backends):
            # filter_backends 就是过滤类们 且 产生的对象 都有 filter_queryset 方法
    		queryset = backend().filter_queryset(self.request, queryset, self)
    	return queryset
    

    2 全局配置 过滤 类们

    filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
    'DEFAULT_FILTER_BACKENDS': [], # 全局配置默认为 [] 
    

    3 局部配置 过滤 类们

    class Test(generics.GenericAPIView, mixins.ListModelMixin):
        ....
        filter_backends = []
        
        def get(self, request, *args, **kwargs):
            self.list(request,args, **kwargs)
    

    4 系统提供 过滤 类们

    restframework 中 找到 filter.py 里面 默认提供了 两个 过滤类 都是继承的BaseFilterBackend且 都有 filter_queryset 方法 他啥都不用继承

    class BaseFilterBackend:
        def filter_queryset(self, request, queryset, view):
            # 直接抛异常
            raise NotImplementedError(".filter_queryset() must be overridden.")
    

    OrderingFilter(排序过滤)

    view视图

    from rest_framework.generics import ListAPIView
    
    # 第一步:drf的OrderingFilter - 排序过滤
    from rest_framework.filters import OrderingFilter
    
    class CarListAPIView(ListAPIView):
        queryset = models.Car.objects.all()
        serializer_class = serializers.CarModelSerializer
    
        # 第二步:局部配置 过滤类 们(全局配置用DEFAULT_FILTER_BACKENDS)
        filter_backends = [OrderingFilter]
    
        # 第三步:OrderingFilter过滤类依赖的过滤条件 => 接口:/cars/?ordering=...
        ordering_fields = ['pk', 'price']
        # eg:/cars/?ordering=-price,pk,先按price降序,如果出现price相同,再按pk升序
        
        # 规则:
        #?ordering=price 按价格升序
        #?ordering=-price 按价格降序
        #?ordering=id 按主键升序
        #?ordering=-price,id 按价格降序,价格相同时按主键升序
    

    **ordering_fields **里面填写字段 (真实存在的)

    接口: 127.0.0.1:8000?ordering=price,name
    查询 按照 price 排序后 在按 name 排序的结果
    支持升序和降序 加-号即可
    

    SearchFilter(查询过滤)

    view视图

    from rest_framework.generics import ListAPIView
    
    # 第一步:drf的SearchFilter - 搜索过滤
    from rest_framework.filters import SearchFilter
    
    class CarListAPIView(ListAPIView):
        queryset = models.Car.objects.all()
        serializer_class = serializers.CarModelSerializer
    
        # 第二步:局部配置 过滤类 们(全局配置用 DEFAULT_FILTER_BACKENDS )
        filter_backends = [SearchFilter]
    
        # 第三步:SearchFilter 过滤类依赖的过滤条件 重点!
        # 接口:/cars/?search=...
        search_fields = ['name', 'price']
        # eg:/cars/?search=1,name和price中包含1的数据都会被查询出
    

    search_fields 里面填写字段 (真实存在的)

    接口: 127.0.0.1:8000?search=1 
    查询 name 和 price 带有 1 的数据
    

    联合使用

    127.0.0.1:8000?search=1$ordering=price,name
    

    DRF分页组件

    入口: restfarmework 中的 pagination.py 提供了 3 个 分页 类 **CursorPagination(游标分页 加密分页) LimitOffsetPagination(偏移分页) PageNumberPagination(基础分页) **

    且 每一个类都有 方法 paginate_queryset 方法

    ef list(self, request, *args, **kwargs):
            
            # 过滤queryset 对象 得到 queryset 对象 方法都在 GenericApiView 里面
            queryset = self.filter_queryset(self.get_queryset())
            # 分页组件
            page = self.paginate_queryset(queryset)
            # 判断是否有 分页 没有就正常执行 有的话就 执行 get_paginated_response
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return self.get_paginated_response(serializer.data)
    
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)
    

    方法也是有 GenericApiView 提供

    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
    
     def paginate_queryset(self, queryset):
            if self.paginator is None:
                return None
            # 调用配置的
            return self.paginator.paginate_queryset(queryset, self.request, view=self)
    

    1 全局配置

    'DEFAULT_PAGINATION_CLASS': None, 默认为None
    

    2 局部配置

    from rest_framework.pagination import PageNumberPagination
    class Test(generics.GenericAPIView, mixins.ListModelMixin):
        queryset = models.Banner.objects.all()
        serializer_class = serializers.BannerModelSerializer
        pagination_class = [PageNumberPagination]
    

    3 PageNumberPagination基础分页

    直接给视图类配置即可 自定义pahenations 修改 参数值 或者直接使用点修改

    pahenations.py

    from rest_framework.pagination import PageNumberPagination
    
    class MyPageNumberPagination(PageNumberPagination):
        # ?page=页码
        page_query_param = 'page'
        # ?page=页面 下默认一页显示的条数
        page_size = 3
        # ?page=页面&page_size=条数 用户自定义一页显示的条数
        page_size_query_param = 'page_size'
        # 用户自定义一页显示的条数最大限制:数值超过5也只显示5条
        max_page_size = 5
    

    views.py

    from rest_framework.generics import ListAPIView
    
    class CarListAPIView(ListAPIView):
        # 如果queryset没有过滤条件,就必须 .all(),不然分页会出问题
        queryset = models.Car.objects.all()
        serializer_class = serializers.CarModelSerializer
        
        # 分页组件 - 给视图类配置分页类即可 - 分页类需要自定义,继承drf提供的分页类即可
        pagination_class = pagenations.MyPageNumberPagination
    

    4 LimitOffsetPagination偏移分页

    使用方式和基本分页器一模一样!

    from rest_framework.pagination import LimitOffsetPagination
    
    class MyPageNumberPagination(LimitOffsetPagination):
        # 不设置offset 和 limit 默认显示3条 只设置offset 默认显示后3条
        default_limit = 3
        # ?offset=从头偏移的条数&limit=要显示的条数
    	limit_query_param = 'limit'
    	offset_query_param = 'offset'
        # 用户自定义一页显示的条数最大限制:数值超过5也只显示5条
    	max_limit = None
    
    127.0.0.1:8000?offset=2&limit=3 # 偏移2条 取3条
    

    5 CursorPagination游标分页 加密分页(了解)

    from rest_framework.pagination import CursorPagination
    
    class MyPageNumberPagination(CursorPagination):
        cursor_query_param = 'cursor'
        # 显示条数
        page_size = 3 
        # 排序
        ordering = '-pk'
        # 用户自定义
        page_size_query_param = None
        # 最大条数
        max_page_size = None
    

    6.自定义过滤器

    filters.py

    # 自定义过滤器,接口:?limit=显示的条数
    class LimitFilter:
        def filter_queryset(self, request, queryset, view):
            # 前台固定用 ?limit=... 传递过滤参数
            limit = request.query_params.get('limit')
            if limit:
                limit = int(limit)
                return queryset[:limit]
            return queryset
    

    views.py

    from rest_framework.generics import ListAPIView
    
    class CarListAPIView(ListAPIView):
        # 如果queryset没有过滤条件,就必须 .all(),不然分页会出问题
        queryset = models.Car.objects.all()
        serializer_class = serializers.CarModelSerializer
        
        # 局部配置 过滤类 们(全局配置用DEFAULT_FILTER_BACKENDS)
        filter_backends = [LimitFilter]
    

    7 django-filter 过滤插件(重点)

    分类查询 大白话来讲就是 苏州地区的酒店 可以叫 上海酒店 也可以叫北京大饭店 如果使用 search查询 上海 关于 起名有上海字的酒店的话 苏州的也会被查出来

    所以我们需要分类查询 将上海地区分类 然后 在查

    安装

    >: pip3 install django-filter
    

    自定义过滤规则类:filters.py

    # django-filter插件过滤器类
    from django_filters.rest_framework.filterset import FilterSet
    from . import models
    
    # 自定义过滤字段
    from django_filters import filters
    class CarFilterSet(FilterSet):
        # 实现区间:field_name关联model表属性,lookup_expr设置过滤规则
        min_price = filters.NumberFilter(field_name='price', lookup_expr='gte')
        max_price = filters.NumberFilter(field_name='price', lookup_expr='lte')
        class Meta:
            model = models.Car
            fields = ['brand', 'min_price', 'max_price']
            # min_price、max_price是自定义字段,需要自己自定义过滤条件
    		# 这样就可以使用?brand=xxx来查询了&min_pirce=12
    

    的视图类:views.py

    from django_filters.rest_framework import DjangoFilterBackend
    from .filters import CourseFilterSet
    class FreeCourseListViewSet(ListModelMixin, GenericViewSet):
        queryset = models.Course.objects.filter(is_delete=False, is_show=True).all()
        serializer_class = serializers.CourseModelSerializer
        
        # 配置过滤组件
        filter_backends = [DjangoFilterBackend]
        # 配置过滤规则的类
        filter_class = CarFilterSet
        # 规则:
        # ?course_category=1 课程分组1所有的课程
        # ?min_price=10 课程价格大于等于10的所有课程
        # ?min_price=10&max_price=100 课程价格大于等于10小于等于100的所有课程
    
  • 相关阅读:
    Python 网络编程 C/S建立Socket连接
    odoo 安装配置
    epoll poll select区别
    SyntaxError :invalid syntax Python常见错误
    TypeError: Can't convert 'int' object to str implicitly Python常见错误
    IndexError: list index out of range Python常见错误
    NameError: name 'foo' is not defined Python常见错误
    IndentationError:unexpected indent”、“IndentationError:unindent does not match any outer indetation level”以及“IndentationError:expected an indented block Python常见错误
    TypeError: 'str' object does not support item assignment Python常见错误
    每周总结
  • 原文地址:https://www.cnblogs.com/lddragon1/p/12189801.html
Copyright © 2020-2023  润新知