使用distinct与order_by关联模型字段时重复记录问题求解
问题翻译
我调用按product__company__name排序的API时,返回结果排序符合预期但存在两条重复记录。查阅Django 3.2文档中distinct方法的说明:
如果你根据关联模型的字段排序,这些字段会被添加到查询的选中列中,这可能会让原本重复的行变得看起来不重复。由于这些额外的列不会出现在返回结果里(它们仅用于支持排序),所以有时候看起来像是返回了非重复结果,但实际并非如此。
我仅需按公司名称对产品进行排序,请问该如何解决此问题?
原代码片段:
def get_queryset(self): qs = MyModel.objects.filter( <logic_code> ) return qs.distinct().order_by("product__company__name")
解决方案
方法1:通过子查询先排序再去重
由于order_by引入的关联表字段会干扰distinct的判断,我们可以先通过子查询完成排序,再基于主键列表获取去重后的结果,同时保留排序顺序:
def get_queryset(self): # 子查询:完成排序并获取主键列表 sorted_pks = MyModel.objects.filter( <logic_code> ).order_by("product__company__name").values_list("pk", flat=True) # 基于主键列表查询,自动去重并保持排序 qs = MyModel.objects.filter(pk__in=sorted_pks).distinct() return qs
方法2:用annotate引入排序字段后去重
将关联的公司名称通过annotate添加为当前模型的查询字段,让distinct能基于主模型字段+排序字段正确判断重复:
from django.db.models import F def get_queryset(self): qs = MyModel.objects.filter( <logic_code> ).annotate(company_name=F("product__company__name")) \ .order_by("company_name") \ .distinct("id", "company_name") return qs
注:Django 3.2支持distinct指定字段,这里指定id(主模型唯一标识)和company_name,避免关联表字段的干扰,确保去重准确。
方法3:针对按公司名称去重的场景(按需使用)
如果你的需求是每个公司名称仅保留一条记录,可以直接在distinct中指定关联字段:
def get_queryset(self): qs = MyModel.objects.filter( <logic_code> ).order_by("product__company__name").distinct("product__company__name") return qs
此方法会保留每个公司名称对应的第一条记录,适合仅需按公司分组展示的场景。
内容的提问来源于stack exchange,提问作者Kev
相关产品推荐
相关产品推荐

