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

Django Rest Framework如何在Serializer的source属性中展示过滤后的数据

问题:自定义Action中Serializer返回全部兴趣数据而非过滤后的结果

我为ModelViewSet添加了自定义action,其中使用related_interests manager函数过滤MyModel实例,但Serializer中设置source获取用户兴趣时,响应返回的是全部兴趣而非过滤后的结果。

ViewSet代码:

class MyModelViewSet(
    viewsets.GenericViewSet,
    mixins.ListModelMixin,
    mixins.CreateModelMixin,
    mixins.RetrieveModelMixin
):
    """ModelViewSet with create, list, retrieve and custom_action operations"""

    queryset = MyModel.objects.all()
    serializer_class = serializers.MyModelSerializer

    @action(detail=False, methods=['post'])
    def custom_action(self, request):
       queryset = MyModel.objects.related_interests()
       serializer = self.serializer_class(queryset, many=True)
       return responses.http_ok_with_dict(serializer.data)

Serializer代码:

class UserWithInterestSerializer(serializers.ModelSerializer):
    licenses = InterestSerializer(read_only=True, source="interest_set", many=True)

    class Meta:
        model = User
        fields = "__all__"


class MyModelSerializer(serializers.ModelSerializer):
    user = UserWithInterestSerializer(read_only=True)

    class Meta:
        model = MyModel
        fields = ["user"]

解决方案

问题核心:你当前的related_interests仅过滤了MyModel实例,但Serializer中user.interest_set是直接从User模型读取全量关联数据,并未关联MyModel的过滤逻辑。以下是几种可行的修复方式:

方式一:使用Prefetch预过滤用户兴趣

修改related_interests方法,通过Prefetch对象指定用户兴趣的过滤条件,并将结果存入自定义属性,再让Serializer读取该属性。

  1. 更新Manager方法:
from django.db.models import Prefetch

class MyModelManager(models.Manager):
    def related_interests(self):
        # 替换为你的兴趣过滤条件
        filtered_interests = Interest.objects.filter(your_filter_condition_here)
        return self.prefetch_related(
            Prefetch(
                'user__interest_set',
                queryset=filtered_interests,
                to_attr='filtered_interests'
            )
        )
  1. 修改Serializer的source指向预过滤后的属性:
class UserWithInterestSerializer(serializers.ModelSerializer):
    licenses = InterestSerializer(read_only=True, source="filtered_interests", many=True)

    class Meta:
        model = User
        fields = "__all__"

方式二:通过SerializerMethodField动态过滤

如果过滤条件依赖请求参数,可在自定义Action中传递上下文,再在Serializer中动态过滤兴趣数据。

  1. 更新自定义Action,传递上下文:
@action(detail=False, methods=['post'])
def custom_action(self, request):
   # 从请求中获取过滤条件,示例为取request.data中的参数
   filter_param = request.data.get('filter_param')
   queryset = MyModel.objects.related_interests()
   serializer = self.serializer_class(
       queryset, 
       many=True, 
       context={'request': request, 'filter_param': filter_param}
   )
   return responses.http_ok_with_dict(serializer.data)
  1. 修改Serializer为动态字段:
class UserWithInterestSerializer(serializers.ModelSerializer):
    licenses = serializers.SerializerMethodField()

    def get_licenses(self, obj):
        filter_param = self.context.get('filter_param')
        # 基于参数过滤兴趣
        filtered_interests = obj.interest_set.filter(your_field=filter_param)
        return InterestSerializer(filtered_interests, many=True).data

    class Meta:
        model = User
        fields = "__all__"

方式三:基于父级MyModel实例过滤

如果用户兴趣需要和当前MyModel实例关联过滤(比如MyModel和Interest存在关联),可通过Serializer的父级实例获取MyModel数据,再过滤兴趣。

修改Serializer:

class UserWithInterestSerializer(serializers.ModelSerializer):
    licenses = serializers.SerializerMethodField()

    def get_licenses(self, obj):
        # 获取父级MyModelSerializer对应的MyModel实例
        my_model = self.parent.instance
        # 根据MyModel实例过滤用户兴趣,替换为你的关联条件
        filtered_interests = obj.interest_set.filter(related_my_model=my_model)
        return InterestSerializer(filtered_interests, many=True).data

    class Meta:
        model = User
        fields = "__all__"

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 10:03:14