You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为ViewSet的自定义action设置django-filter的FilterSet

Django ViewSet自定义Action接入django-filter的实现方案

首先完成基础配置:

  1. 安装依赖:pip install django-filter djangorestframework
  2. 在项目配置文件中注册app并配置默认过滤后端:
# settings.py
INSTALLED_APPS = [
    # 其他内置/自定义应用
    'rest_framework',
    'django_filters',
]

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': [
        'django_filters.rest_framework.DjangoFilterBackend',
        # 可按需追加搜索、排序等其他过滤后端
    ]
}

你可以根据代码习惯选择以下两种生效稳定的实现方式:


方案1:手动实例化FilterSet(全版本兼容,逻辑可控)

这种方式不受DRF版本、ViewSet继承链影响,适合复杂业务场景。只需要在自定义action逻辑中,将待过滤的queryset、请求参数传入FilterSet,校验通过后取过滤结果即可:

from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Product
from .filters import ProductFilter  # 你自定义的FilterSet类
from .serializers import ProductSerializer


class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filterset_class = ProductFilter  # 内置list接口默认使用的过滤类

    # 示例自定义action:返回所有在售商品,支持ProductFilter的所有过滤规则
    @action(detail=False, methods=['get'])
    def on_sale(self, request):
        # 1. 拿到当前action对应的原始queryset
        base_qs = Product.objects.filter(is_on_sale=True)
        # 2. 实例化过滤器,传入请求参数、原始queryset
        filter_set = ProductFilter(
            data=request.query_params,
            queryset=base_qs,
            request=request
        )
        # 3. 校验过滤参数合法性
        if not filter_set.is_valid():
            return Response(filter_set.errors, status=400)
        # 4. 取过滤后的结果,走正常的分页、序列化逻辑
        filtered_qs = filter_set.qs
        page = self.paginate_queryset(filtered_qs)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(filtered_qs, many=True)
        return Response(serializer.data)

方案2:给Action绑定过滤配置(代码更简洁)

DRF的@action装饰器支持直接给单个action指定过滤后端和过滤类,配置后和内置的list接口逻辑完全一致,不需要手动编写FilterSet实例化代码:

from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Product
from .filters import ProductFilter
from .serializers import ProductSerializer


class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filterset_class = ProductFilter

    @action(
        detail=False,
        methods=['get'],
        # 为当前action指定过滤后端
        filter_backends=[DjangoFilterBackend],
        # 为当前action指定使用的FilterSet,可和全局配置不同
        filterset_class=ProductFilter
    )
    def on_sale(self, request):
        # 调用ViewSet自带的filter_queryset方法,自动完成过滤
        base_qs = Product.objects.filter(is_on_sale=True)
        filtered_qs = self.filter_queryset(base_qs)
        # 后续分页、序列化逻辑和方案1完全一致
        page = self.paginate_queryset(filtered_qs)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(filtered_qs, many=True)
        return Response(serializer.data)

注意事项

  • 针对detail=True的单资源操作action(路由格式为/products/{id}/xxx/),一般不需要过滤集合类queryset,如果需要过滤当前资源关联的子对象集合,把关联对象的queryset传入FilterSet即可,逻辑和上述示例一致。
  • 如果多个自定义action共用同一个FilterSet,可以把FilterSet定义为ViewSet的类属性,action内直接通过self.filterset_class引用即可,不需要重复导入或传参。
  • 不要在DRF视图中混用原生Django的Filter后端,必须使用django_filters.rest_framework.DjangoFilterBackend,否则会出现响应格式不兼容、分页失效等问题。

内容的提问来源于stack exchange,提问作者Seofale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 20:03:24