Django Rest Framework之过滤器

一:原始过滤方法

默认情况下 DRF generic list view 会返回整个 queryset 查询结果,但通常业务只是需要其中一部分,这种情况下就需要使用 “过滤器” 来限制返回结果集。
最原始的方式是继承 GenericAPIView 类或使用继承了 GenericAPIView 的类,然后重写 .get_queryset() 方法 比如:

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    # queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = Pagination

    def get_queryset(self):
        queryset = Goods.objects.all()
        price_min = self.request.query_params.get('price_min', 0)
        if price_min:
            queryset = Goods.objects.filter(shop_price__gt = int(price_min))
        return queryset

这里注意:由于在类中没有指定queryset,在访问接口时会报如下错误

assert queryset is not None, '`basename` argument not specified, and could ' \
AssertionError: `basename` argument not specified, and could not automatically determine the name from the viewset, as it does not have a `.queryset` attribute.

解决方案是在路由中加basename参数:

from rest_framework.routers import DefaultRouter
from goods import views

router = DefaultRouter()
router.register(r'^goods', views.GoodsListViewSet, basename = 'goods')

这样即可在接口url中添加查询参数过滤数据:
Django Rest Framework之过滤器
这样做如果在过滤条件复杂的情况下,代码会显得过于冗余,而且有可能大部分代码一直在重复实现类似的功能。

二:DjangoFilterBackend

文档:https://www.django-rest-framework.org/api-guide/filtering/#djangofilterbackend

安装django-filter:

pip install django-filter

注册APP:

INSTALLED_APPS = [
    'django_filters'
]

DjangoFilterBackend为默认的过滤类:

# 可以在settings配置文件添加如下选项,因为是默认的类,不添加也可
REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}

在视图类中指定过滤类:

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):

    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = Pagination
    filter_backends = [DjangoFilterBackend]
    filter_fields = ['name', 'shop_price']		# 需要过滤的字段

这里注意: 使用了Django-filter后,queryset不可以再使用切片,如queryset使用了切片会报如下错误:

queryset = Goods.objects.all().order_by('id')[:20]
# 报错信息如下
AssertionError: Cannot filter a query once a slice has been taken.

再次访问接口时,页面会多出一个Filter的按钮
Django Rest Framework之过滤器
Django Rest Framework之过滤器
注意:上面的商品名必须要与数据库中的已有商品名完全一致才可以被过滤出来(不同于模糊搜索)
Django Rest Framework之过滤器
现在需求变了,如:name字段需要模糊过滤,而price字段可以是一个价格区间。
那么可以通过自定义的过滤类来扩展默认的过滤类功能

from django_filters import rest_framework as filters
from goods.models import Goods

class GoodsFilter(filters.FilterSet):
    # 自定义商品的过滤类
    name = filters.CharFilter(field_name = 'name', lookup_expr='icontains') # 等价于 sql 中的 like; i 表示忽略大小写
    min_price = filters.NumberFilter(field_name='shop_price', lookup_expr='gte')
    max_price = filters.NumberFilter(field_name='shop_price', lookup_expr='lte')
    class Meta:
        model = Goods
        fields = ['name', 'min_price', 'max_price']

视图类中使用自定义的过滤类:

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):

    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = Pagination
    filter_backends = [DjangoFilterBackend]
    filter_fields = ['name', 'shop_price']
    filter_class = GoodsFilter

Django Rest Framework之过滤器
Django Rest Framework之过滤器

三:SearchFilter

这个类提供了对单一字段的搜素功能,在使用后 DRF 数据浏览页面会出现 SearchFilter 的控制器。在配置时只需要将 view 中添加 search_fields 属性,且将需要搜索的 Model 字段放入 tuple 中传给 search_fields。

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):

    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = Pagination
    filter_backends = [DjangoFilterBackend, filters.SearchFilter]
    filter_fields = ['name', 'shop_price']
    filter_class = GoodsFilter
    search_fields = ['name', 'goods_brief', 'goods_desc']

默认情况下,搜索是大小写敏感的局部匹配。搜索参数可以包含多个搜索定义,且用空格或者逗号分开。如果使用了多个查询字段则返回结果集必须符合所有所有字段查询条件。
Django Rest Framework之过滤器
查询设置:

'^' Starts-with search.
'=' Exact matches.
'@' Full-text search 模糊查询 (Currently only supported Django's MySQL backend.)
'$' Regex search

如:search_fields = (’@username’, ‘=email’)

四:OrderingFilter

OrderingFilter 类支持对单个查询字段结果集进行排序。

from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):

    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = Pagination
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filter_fields = ['name', 'shop_price']
    filter_class = GoodsFilter
    search_fields = ['name', 'goods_brief', 'goods_desc']
    ordering_fields = ['sold_num', 'add_time']

Django Rest Framework之过滤器

发布了45 篇原创文章 · 获赞 3 · 访问量 1508

猜你喜欢

转载自blog.csdn.net/pcn01/article/details/104062976