使用DRF的过滤组件, 排序组件 django-filter前提都是群查接口,并且使用的视图类都要直接或间接的继承GenericAPIView类
数据准备
- 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()),
SearchFilter 搜索过滤组件
使用步骤:
1.导入搜索过滤器
from rest_framework.filters import 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.导入搜索过滤
from rest_framework.filters import 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升序
自定义过滤类
源码: GenericAPIView类中的filter_queryset方法调用过滤,排序组件
class GenericAPIView(views.APIView):
...
# 配置过滤器路径
filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
...
def filter_queryset(self, queryset): # self是视图类对象
# 若自己的视图列中配置了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 = [OrderingFilter, SearchFilter, LimitFilter]
search_fields = ['name', 'price']
ordering_fields = ['pk', 'price']
eg:/cars/?search=1?limit=5?ordering=-price,pk,
name和price中包含1的数据都会被查询出,先按price降序,如果出现price相同,再按pk升序并且显示5条
django-filter 过滤器插件
安装
pip3 install django-filter
settings.py中配置
INSTALLED_APPS = [
...
'django_filters', # 需要注册应用,
]
全局配置
REST_FRAMEWORK = {
...
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}
使用
- 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间的宝马牌汽车