drf过滤组件、分页组件与def-filter筛选插件
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</span><span style="color: #008000;">#</span><span style="color: #008000;"> 分页组件 - 给视图类配置分页类即可 - 分页类需要自定义,继承drf提供的分页类即可</span> pagination_class = pagenations.MyPageNumberPagination</pre>
偏移分页组件
pahenations.py
from rest_framework.pagination import LimitOffsetPagination class MyLimitOffsetPagination(LimitOffsetPagination): # ?offset=从头偏移的条数&limit=要显示的条数 limit_query_param = 'limit' offset_query_param = 'offset'<span style="color: #008000;">#</span><span style="color: #008000;"> ?不传offset和limit默认显示前3条,只设置offset就是从偏移位往后再显示3条</span> default_limit = 3 <span style="color: #008000;">#</span><span style="color: #008000;"> ?limit可以自定义一页显示的最大条数</span> max_limit = 5<span style="color: #000000;">
# 只使用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</span><span style="color: #008000;">#</span><span style="color: #008000;"> 分页组件 - 给视图类配置分页类即可 - 分页类需要自定义,继承drf提供的分页类即可</span> pagination_class = pagenations.MyLimitOffsetPagination</pre>
游标分页组件
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</span><span style="color: #008000;">#</span><span style="color: #008000;"> 分页组件 - 给视图类配置分页类即可 - 分页类需要自定义,继承drf提供的分页类即可</span> pagination_class = pagenations.MyCursorPagination</pre>
自定义过滤类
源码:
class GenericAPIView(views.APIView): ... # 配置过滤器路径 filter_backends = api_settings.DEFAULT_FILTER_BACKENDS ...</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> filter_queryset(self, queryset): </span><span style="color: #008000;">#</span><span style="color: #008000;"> 若自己的视图列中配置了filter_backends=[过滤类] 就走视图类中的</span> <span style="color: #0000ff;">for</span> backend <span style="color: #0000ff;">in</span><span style="color: #000000;"> list(self.filter_backends): </span><span style="color: #008000;">#</span><span style="color: #008000;"> 当时视图类中配置了filter_backends=[过滤类]</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 下面这步会调用我们自己定义的过滤类的filter_queryset方法</span> queryset =<span style="color: #000000;"> backend().filter_queryset(self.request, queryset, self) </span><span style="color: #0000ff;">return</span> queryset</pre>
使用:
# 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</span><span style="color: #008000;">#</span><span style="color: #008000;"> 局部配置 过滤类 们(全局配置用DEFAULT_FILTER_BACKENDS)</span> <span style="color: #ff0000;">filter_backends</span> = [LimitFilter]</pre>
过滤器插件: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</span><span style="color: #008000;">#</span><span style="color: #008000;"> 局部配置 过滤类 们(全局配置用DEFAULT_FILTER_BACKENDS)</span> filter_backends =<span style="color: #000000;"> [DjangoFilterBackend] </span><span style="color: #008000;">#</span><span style="color: #008000;"> django-filter过滤器插件使用</span> filter_class =<span style="color: #000000;"> CarFilterSet </span><span style="color: #008000;">#</span><span style="color: #008000;"> 接口:?brand=...&min_price=...&max_price=...</span> <strong><span style="color: #ff6600;"># eg:?brand=宝马&min_price=5&max_price=10 => 5~10间的宝马牌汽车 </span></strong></pre>