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

Django REST:如何基于SerializerMethodField实现自定义过滤?

解决DRF中通过Serializer计算字段过滤查询集的问题

问题背景

需要基于Serializer中通过SerializerMethodField计算的非模型字段is_favorite(判断当前用户是否收藏该食谱)过滤Django REST Framework的返回结果,但现有自定义过滤器未生效。

原因分析

is_favorite是Serializer层面的计算字段,并非Recipe模型的数据库字段,无法直接通过数据库查询过滤。之前的过滤器写法试图针对模型中不存在的is_favorite字段操作,自然无法生效。此外,过滤逻辑依赖当前请求的用户信息,必须在过滤器中获取request对象才能完成关联判断。

解决方案

1. 修正自定义过滤器

修改RecipeFilter类,直接关联Favorite模型并基于当前用户过滤Recipe查询集:

class RecipeFilter(rest_framework.FilterSet):
    tags = ModelMultipleChoiceFilter(
        field_name='tags__slug',
        to_field_name="slug",
        queryset=Tag.objects.all()
    )
    # 移除无效的field_name,直接指定过滤方法
    favorite = BooleanFilter(method='filter_favorite')

    def filter_favorite(self, queryset, name, value):
        user = self.request.user
        # 匿名用户无收藏数据,根据参数返回对应结果
        if user.is_anonymous:
            return queryset.none() if value else queryset
        
        # 获取当前用户收藏的所有食谱ID
        favorite_recipe_ids = Favorite.objects.filter(user=user).values_list('recipe_id', flat=True)
        
        if value:
            # 返回用户收藏的食谱
            return queryset.filter(id__in=favorite_recipe_ids)
        else:
            # 返回用户未收藏的食谱
            return queryset.exclude(id__in=favorite_recipe_ids)

    class Meta:
        model = Recipe
        fields = ['tags', 'favorite']

2. 调整视图配置

确保视图正确使用过滤器,并根据请求动作切换序列化器(保证输出接口能返回is_favorite字段):

class RecipeViewSet(ModelViewSet):
    queryset = Recipe.objects.all()
    permission_classes = [IsAdminOrAuthorOrReadOnly, ]
    pagination_class = LimitPageNumberPagination
    filter_backends = [DjangoFilterBackend]
    # 移除filterset_fields避免与filter_class冲突
    filter_class = RecipeFilter

    # 根据请求动作选择对应序列化器
    def get_serializer_class(self):
        if self.action in ['list', 'retrieve']:
            return RecipeOutSerializer
        return RecipeInSerializer

关键说明

  • 过滤逻辑直接操作数据库关联表Favorite,通过子查询获取用户收藏的食谱ID列表,再对Recipe查询集进行过滤,保证性能。
  • 处理了匿名用户的边界情况:匿名用户无收藏数据,当favorite=true时返回空集,否则返回全部食谱。
  • 视图中通过get_serializer_class区分输入输出序列化器,确保列表/详情接口能正确返回is_favorite计算字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 23:10:31