Джанго выбрать только строки с повторяющимися значениями полей
предположим, что у нас есть модель в django, определенная следующим образом:
class Literal:
name = models.CharField(...)
...
поле Name не является уникальным и, следовательно, может иметь повторяющиеся значения. Мне нужно выполнить следующую задачу: Выберите все строки из модели, которые имеют по меньшей мере одно повторяющееся значение на
5 ответов:
попробуй:
from django.db.models import Count Literal.objects.values('name') .annotate(Count('id')) .order_by() .filter(id__count__gt=1)
это так близко, как вы можете сделать с Django. Проблема в том, что это вернет
ValuesQuerySet
Сname
иcount
. Однако затем вы можете использовать это для построения регулярного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 со всеми повторяющимися именами. Однако затем вы можете использовать это для создания обычного набора запросов, возвращая его в другой запрос. Django orm достаточно умен, чтобы объединить их в один запрос:
Literal.objects.filter(name__in=dups)
дополнительные звонка .значения ('name') после вызова аннотации выглядят немного странно. Без этого подзапрос не выполняется. Дополнительные значения обманывают orm, выбирая только столбец name для подзапроса.
попробуйте использовать агрегация
Literal.objects.values('name').annotate(name_count=Count('name')).exclude(name_count=1)
Если вы используете 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