drf框架 - 过滤组件 | 分页组件 | 过滤器插件

drf框架 接口过滤条件

群查接口各种筛选组件数据准备

models.py
class Car(models.Model):
    name = models.CharField(max_length=16, unique=True, verbose_name='车名')
    price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='价格')
    brand = models.CharField(max_length=16, verbose_name='品牌')
​
    class Meta:
        db_table = 'api_car'
        verbose_name = '汽车表'
        verbose_name_plural = verbose_name
​
    def __str__(self):
        return self.name

 

admin.py
admin.site.register(models.Car)

 

serializers.py
class CarModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Car
        # 参与序列化的字段
        fields = ['name', 'price', 'brand']

 

views.py
# Car的群查接口
from rest_framework.generics import ListAPIView
​
class CarListAPIView(ListAPIView):
    queryset = models.Car.objects.all()
    serializer_class = serializers.CarModelSerializer

 

urls.py
url(r'^cars/$', views.CarListAPIView.as_view()),

 

drf过滤组件

搜索过滤组件 | SearchFilter

使用步骤:
1.导入搜索过滤器 SearchFilter
2.局部配置 filter_backends = [SearchFilter]
3.局部配置过滤类依赖的过滤条件(字段) search_fields = ['name', 'price'] 注意:依赖的过滤字段只能配置序列化类中fields里配置的字段
接口使用样式:
/cars/?search=...
# eg:/cars/?search=1,name和price中包含1的数据都会被查询出

 

案例:

views.py
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的数据都会被查询出

 

排序过滤组件 | OrderingFilter

使用步骤:
1.导入搜索过滤 OrderingFilter
2.局部配置 filter_backends = [OrderingFilter]
3.局部配置过滤类依赖的过滤条件(字段) ordering_fields = ['pk', 'price']
接口使用样式:
/cars/?ordering=...
# eg:/cars/?ordering=-price,pk,先按price降序,如果出现price相同,再按pk升序

 

案例:

views.py
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升序

 

drf分页组件

自定义分页组件:

1.pahenations.py中自定义分页类(基础分页类/偏移分页类/游标分页类)
2.视图类中配置自定义的分页类: pagination_class = 自定义分页类

 

基础分页组件

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

 

偏移分页组件

pahenations.py
from rest_framework.pagination import LimitOffsetPagination
class MyLimitOffsetPagination(LimitOffsetPagination):
    # ?offset=从头偏移的条数&limit=要显示的条数
    limit_query_param = 'limit'
    offset_query_param = 'offset'
    
    # ?不传offset和limit默认显示前3条,只设置offset就是从偏移位往后再显示3条
    default_limit = 3
    
    # ?limit可以自定义一页显示的最大条数
    max_limit = 5# 只使用limit结合ordering可以实现排行前几或后几
    # eg: ?ordering=-price&limit=2  => 价格前2

 

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.MyLimitOffsetPagination

 

游标分页组件

pahenations.py
# 注:必须基于排序规则下进行分页
# 1)如果接口配置了OrderingFilter过滤器,那么url中必须传ordering
# 1)如果接口没有配置OrderingFilter过滤器,一定要在分页类中声明ordering按某个字段进行默认排序
from rest_framework.pagination import CursorPagination
class MyCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'
    page_size = 3
    page_size_query_param = 'page_size'
    max_page_size = 5
    ordering = '-pk'

 

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.MyCursorPagination

 

自定义过滤类

源码:

class GenericAPIView(views.APIView):
    ...
    # 配置过滤器路径
    filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
    ...
    
    def filter_queryset(self, queryset):
        # 若自己的视图列中配置了filter_backends=[过滤类] 就走视图类中的
        for backend in list(self.filter_backends):
            # 当时视图类中配置了filter_backends=[过滤类]
            # 下面这步会调用我们自己定义的过滤类的filter_queryset方法
            queryset = backend().filter_queryset(self.request, queryset, self)
        return queryset

 

使用:

# 1.自定义过滤类,重写filter_queryset方法
# 2.在视图类中配置filter_backends = [自定义过滤类]
补充:
自定义过滤类不需要继承GenericAPIView,因为视图类继承了ListAPIView, ListAPIView本来就继承GenericAPIView
我们自定义的过滤类要在视图类中配置,当源码中的GenericAPIView要调用过滤类时就会调用我们在视图类中配置的自定义过滤类,从而调用filter_query方法

 

filters.py

class LimitFilter:
    # 重写filter_queryset方法
    def filter_queryset(self, request, queryset, view):
        # 从get请求中获取limit的值
        limit_mun = request.query_params.get('limit')
        if limit_mun:
            limit_mun = int(limit_mun)
            # 将queryset列表按limit_num切分
            return queryset[:limit_mun]
        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]

 

过滤器插件:django-filter

安装
>: pip3 install django-filter

 

过滤条件层:自定义api/filters.py
from django_filters.rest_framework.filterset import FilterSet
from . import models
from django_filters import filters
​
class CarFilterSet(FilterSet):
    # 自定义过滤字段
    max_price = filters.NumberFilter(
        field_name='price',  # 该自定义字段关联的model类表中的字段
        lookup_expr='gte',  # 查找的条件  'gte':大于等于
    )
    min_price = filters.NumberFilter(
        field_name='price',  # 该自定义字段关联的model类表中的字段
        lookup_expr='lte',  # 查找的条件  'lte':小于等于
    )
    class Meta:
        model = models.Car
        fields = ['brand', 'min_price', 'max_price']
        # brand是model中存在的字段,一般都是可以用于分组的字段
        # min_price、max_price是自定义字段,需要自己自定义过滤条件

 

视图层:views.py

# django-filter插件过滤器
from django_filters.rest_framework import DjangoFilterBackend
from .filters import CarFilterSet
​
class CarListAPIView(ListAPIView):
    queryset = models.Car.objects.all()
    serializer_class = serializers.CarModelSerializer
    
    # 局部配置 过滤类 们(全局配置用DEFAULT_FILTER_BACKENDS)
    filter_backends = [DjangoFilterBackend]
    
    # django-filter过滤器插件使用
    filter_class = CarFilterSet
    # 接口:?brand=...&min_price=...&max_price=...
    # eg:?brand=宝马&min_price=5&max_price=10 => 5~10间的宝马牌汽车
    

 


   

 

 

 

 

posted @ 2019-10-24 19:47  waller  阅读(341)  评论(0编辑  收藏  举报