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读取该属性。
- 更新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' ) )
- 修改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中动态过滤兴趣数据。
- 更新自定义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)
- 修改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
相关产品推荐
相关产品推荐

