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

跨ManyToMany用related_name注解Django Queryset避免重复条目方法

解决方案

问题原因

你当前写法返回重复ListEntry对象,是因为F()跨多对多关系查询时会执行JOIN操作,每个关联的CompanySubType都会生成一行独立的查询结果,所以关联多个子类型的项目会对应多条重复的ListEntry记录。另外你代码中的关联路径list_pmatt__project_subtype是笔误,正确路径应为list_project__project_subtype。

方案1:使用ArrayAgg聚合(PostgreSQL环境优先选择,最简洁)

PostgreSQL数据库支持数组类型的聚合函数ArrayAgg,可以直接将多对多关联的多个值聚合成一个数组返回,不需要额外处理:

  1. 导入聚合函数
from django.db.models import ArrayAgg
  1. 改写查询逻辑
list_entry_qs = ListEntry.objects.prefetch_related(
    'list_project', 'list_reviewer'
).annotate(
    # distinct=True避免出现重复的子类型值
    subtypes=ArrayAgg('list_project__project_subtype__project_subtype', distinct=True)
).all()

注解得到的subtypes字段就是包含所有关联子类型的列表,直接传给DRF序列化器,用serializers.ListField(child=serializers.CharField())即可正常序列化。

方案2:序列化层处理(全数据库兼容)

如果你用的是MySQL等不支持ArrayAgg的数据库,可以通过预加载关联数据+序列化器自定义字段实现,性能和方案1一致:

  1. 优化查询逻辑,预加载关联的子类型数据,避免N+1查询
from django.db.models import Prefetch

list_entry_qs = ListEntry.objects.prefetch_related(
    'list_reviewer',
    # 预加载项目关联的所有子类型
    Prefetch('list_project', queryset=CompanyProject.objects.prefetch_related('project_subtype'))
).all()
  1. 为ListEntry序列化器新增子类型字段
from rest_framework import serializers

class ListEntrySerializer(serializers.ModelSerializer):
    subtypes = serializers.SerializerMethodField()
    
    class Meta:
        model = ListEntry
        fields = ['id', 'list_project', 'list_reviewer', 'subtypes']
    
    def get_subtypes(self, obj):
        # 直接调用模型中已定义的方法返回子类型列表
        return obj.list_project.get_project_subtypes()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 14:06:03