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 namecampo.
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 fieldvalues_list('name', flat=True)Countanotació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 lacountque 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 sumycountlugar.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
ValuesQuerySetcon todos los nombres duplicados. Sin embargo, puede usar esto para construir un regularQuerySetrealimentá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 BYclá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