supongamos que tenemos un modelo en django definido de la siguiente manera:
class Literal:
name = models.CharField(...)
...
El campo de nombre no es único y, por lo tanto, puede tener valores duplicados. Necesito realizar la siguiente tarea: Seleccionar todas las filas del modelo que tengan al menos un valor duplicado del name
campo.
Sé cómo hacerlo usando SQL simple (puede que no sea la mejor solución):
select * from literal where name IN (
select name from literal group by name having count((name)) > 1
);
Entonces, ¿es posible seleccionar esto usando django ORM? ¿O una mejor solución SQL?
sql
django
django-orm
dragón
fuente
fuente
Literal.objects.values('name').annotate(name_count=Count('name')).filter(name_count__gt=1)
?Cannot resolve keyword 'id_count' into field
values_list('name', flat=True)
Count
anotación se guarde como, el valor predeterminado es[field]__count
. Sin embargo, esa sintaxis de doble subrayado es también la forma en que Django interpreta que desea hacer una combinación. Entonces, esencialmente cuando intentas filtrar eso, Django piensa que estás tratando de hacer una unión con lacount
que obviamente no existe. La solución es especificar un nombre para el resultado de su anotación, es decir,annotate(mycount=Count('id'))
y luego filtrar en sumycount
lugar.values('name')
después de su llamada para anotar, puede eliminar la comprensión de la lista y decirLiteral.objects.filter(name__in=dupes)
cuál permitirá que todo esto se ejecute en una sola consulta.Esto fue rechazado como edición. Así que aquí está una mejor respuesta.
Esto devolverá un
ValuesQuerySet
con todos los nombres duplicados. Sin embargo, puede usar esto para construir un regularQuerySet
realimentándolo en otra consulta. El ORM de django es lo suficientemente inteligente como para combinarlos en una sola consulta:La llamada adicional a
.values('name')
después de la llamada de anotación parece un poco extraña. Sin esto, la subconsulta falla. Los valores adicionales engañan al ORM para que solo seleccione la columna de nombre para la subconsulta.fuente
.order_by()
?GROUP BY
cláusula SQL y eso rompe las cosas. Lo descubrí al jugar con Subconsulta (en la que haces agrupaciones muy similares a través de.values()
)intenta usar agregación
fuente
En caso de que use PostgreSQL, puede hacer algo como esto:
El resultado es esta consulta SQL bastante simple:
fuente
Si desea obtener solo la lista de nombres pero no los objetos, puede usar la siguiente consulta
fuente