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

如何在Django中过滤多对多关联的public=True Content适配DRF序列化

解决Django多对多关联序列化时过滤子对象的问题

你的核心需求是:序列化Collection模型时,只展示其关联的public == True的Content对象。原代码存在两个问题:

  • 视图中的filter(content_set__enable=True)字段名错误(应为content_set__public=True),且该过滤仅筛选出至少包含一个公开Content的Collection,无法控制序列化时返回的Content列表;
  • 序列化器直接调用content_set会返回该Collection下所有关联Content,不受public状态限制。

下面是两种可行的解决方法:

方法一:使用SerializerMethodField自定义字段

直接在CollectionSerializer中通过自定义方法过滤符合条件的Content:

修改serializers.py:

class ContentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Content
        fields = ["author"]


class CollectionSerializer(serializers.ModelSerializer):
    # 替换原自动关联的content_set为自定义字段
    content_set = serializers.SerializerMethodField()

    def get_content_set(self, obj):
        # 过滤当前Collection下public=True的Content
        filtered_contents = obj.content_set.filter(public=True)
        return ContentSerializer(filtered_contents, many=True).data

    class Meta:
        model = Collection
        fields = [
            "title",
            "content_set",
        ]

视图部分可按需调整:

class CollectionViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Collection.objects.all()
    serializer_class = CollectionSerializer
    permission_classes = [permissions.AllowAny]

    # 若需仅返回包含至少一个公开Content的Collection,保留此方法
    def get_queryset(self):
        return Collection.objects.filter(content_set__public=True)

方法二:使用Prefetch优化查询性能

如果数据量较大,方法一会产生N+1查询问题(每个Collection单独查询一次Content)。可通过Prefetch对象在查询Collection时预取过滤后的Content,提升性能:

修改views.py:

from django.db.models import Prefetch

class CollectionViewSet(viewsets.ReadOnlyModelViewSet):
    serializer_class = CollectionSerializer
    permission_classes = [permissions.AllowAny]

    def get_queryset(self):
        # 预取过滤后的Content,指定自定义关联名称
        prefetch = Prefetch(
            'content_set',
            queryset=Content.objects.filter(public=True),
            to_attr='filtered_contents'
        )
        # 若需筛选包含公开Content的Collection,追加filter(content_set__public=True)
        return Collection.objects.prefetch_related(prefetch)

修改serializers.py,使用预取的字段:

class ContentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Content
        fields = ["author"]


class CollectionSerializer(serializers.ModelSerializer):
    # 关联预取的filtered_contents字段
    content_set = ContentSerializer(source='filtered_contents', many=True, read_only=True)

    class Meta:
        model = Collection
        fields = [
            "title",
            "content_set",
        ]

效果验证

两种方法最终都会输出你期望的JSON格式:

[
    {
        "title": "Foo",
        "content_set": [
            {
                "author": "Jane Doe"
            }
        ]
    }
]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 00:20:01