Django只select具有重复字段值的行

假设我们在django中有一个模型定义如下:

class Literal: name = models.CharField(...) ... 

名称字段不是唯一的,因此可能有重复的值。 我需要完成以下任务:从模型中select至less有一个 name字段重复值的所有行。

我知道如何使用纯SQL(可能不是最好的解决scheme):

 select * from literal where name IN ( select name from literal group by name having count((name)) > 1 ); 

那么,是否可以使用django ORM来select它? 或更好的SQL解决scheme?

尝试:

 from django.db.models import Count Literal.objects.values('name') .annotate(Count('id')) .order_by() .filter(id__count__gt=1) 

这跟Django一样。 问题是,这将返回一个ValuesQuerySet只有namecount 。 但是,您可以使用它来构造一个常规QuerySet是将其反馈到另一个查询中:

 dupes = Literal.objects.values('name') .annotate(Count('id')) .order_by() .filter(id__count__gt=1) Literal.objects.filter(name__in=[item['name'] for item in dupes]) 

这被作为编辑拒绝。 所以这里是一个更好的答案

 dups = ( Literal.objects.values('name') .annotate(count=Count('id')) .values('name') .order_by() .filter(count__gt=1) ) 

这将返回一个ValuesQuerySet与所有重复的名称。 但是,您可以使用它将其反馈到另一个查询中来构造一个常规QuerySet。 django orm很聪明,可以将它们组合成一个查询:

 Literal.objects.filter(name__in=dups) 

在注释调用之后额外的调用.values('name')看起来有点奇怪。 没有这个,子查询就失败了。 额外的值会使orm进入只为子查询select名称列。

尝试使用聚合

 Literal.objects.values('name').annotate(name_count=Count('name')).exclude(name_count=1) 

如果您只想得到名称列表而不是对象,则可以使用以下查询

 repeated_names = Literal.objects.values('name').annotate(Count('id')).order_by().filter(id__count__gt=1).values_list('name', flat='true') 

如果你使用PostgreSQL,你可以这样做:

 from django.contrib.postgres.aggregates import ArrayAgg from django.db.models import Func, Value duplicate_ids = (Literal.objects.values('name') .annotate(ids=ArrayAgg('id')) .annotate(c=Func('ids', Value(1), function='array_length')) .filter(c__gt=1) .annotate(ids=Func('ids', function='unnest')) .values_list('ids', flat=True)) 

它导致这个相当简单的SQL查询:

 SELECT unnest(ARRAY_AGG("app_literal"."id")) AS "ids" FROM "app_literal" GROUP BY "app_literal"."name" HAVING array_length(ARRAY_AGG("app_literal"."id"), 1) > 1