Consulto un modelo:
Members.objects.all()
Y vuelve:
Eric, Salesman, X-Shop
Freddie, Manager, X2-Shop
Teddy, Salesman, X2-Shop
Sean, Manager, X2-Shop
Lo que quiero es conocer la mejor forma de Django para enviar una group_by
consulta a mi base de datos, como:
Members.objects.all().group_by('designation')
Lo cual no funciona, por supuesto. Sé que podemos hacer algunos trucos django/db/models/query.py
, pero tengo curiosidad por saber cómo hacerlo sin parches.
python
django
django-models
simplemente duro
fuente
fuente
Members.objects.filter(date=some_date).values('designation').annotate(dcount=Count('designation'))
Members.objects.order_by('disignation').values('designation').annotate(dcount=Count('designation'))
Una solución fácil, pero no la forma correcta es usar SQL sin formato :
Otra solución es usar la
group_by
propiedad:Ahora puede iterar sobre la variable de resultados para recuperar sus resultados. Tenga en cuenta que
group_by
no está documentado y puede modificarse en futuras versiones de Django.Y ... ¿por qué quieres usar
group_by
? Si no usa la agregación, puede usarlaorder_by
para lograr un resultado similar.fuente
También puede usar la
regroup
etiqueta de plantilla para agrupar por atributos. De los documentos:Se ve como esto:
También funciona en
QuerySet
s, creo.fuente: https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#regroup
editar: tenga en cuenta que la
regroup
etiqueta no funciona como cabría esperar si su lista de diccionarios no está ordenada por clave. Funciona iterativamente. Así que ordene su lista (o conjunto de consultas) por la clave del mero antes de pasarla a laregroup
etiqueta.fuente
Necesita hacer SQL personalizado como se ejemplifica en este fragmento:
SQL personalizado a través de subconsulta
O en un administrador personalizado como se muestra en los documentos en línea de Django:
Agregar métodos de administrador adicionales
fuente
Django no admite grupos libres por consultas . Lo aprendí de la muy mala manera. ORM no está diseñado para admitir cosas como lo que desea hacer, sin usar SQL personalizado. Estás limitado a:
cr.execute
oraciones (y un análisis del resultado hecho a mano)..annotate()
(el grupo por oraciones se realiza en el modelo secundario para .annotate (), en ejemplos como agregar lines_count = Count ('lines'))).qs
Puede llamar a un conjunto de consultas,qs.query.group_by = ['field1', 'field2', ...]
pero es arriesgado si no sabe qué consulta está editando y no tiene garantía de que funcionará y no romperá las partes internas del objeto QuerySet. Además, es una API interna (no documentada) a la que no debe acceder directamente sin arriesgarse a que el código ya no sea compatible con futuras versiones de Django.fuente
Hay un módulo que le permite agrupar modelos de Django y seguir trabajando con un QuerySet en el resultado: https://github.com/kako-nawao/django-group-by
Por ejemplo:
'book / books.html'
La diferencia con las consultas
annotate
/aggregate
basic Django es el uso de los atributos de un campo relacionado, por ejemplobook.author.last_name
.Si necesita las PK de las instancias que se han agrupado, agregue la siguiente anotación:
NOTA:
ArrayAgg
es una función específica de Postgres, disponible desde Django 1.9 en adelante: https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/aggregates/#arrayaggfuente
values
método. Es para un propósito diferente, creo.values
es un SQLselect
mientras quegroup_by
es un SQLgroup by
(como su nombre indica ...). ¿Por qué el voto negativo? Estamos utilizando dicho código en producción para implementargroup_by
declaraciones complejas .group_by
"se comporta principalmente como el método de valores, pero con una diferencia ..." El documento no menciona SQLGROUP BY
y el caso de uso que proporciona no sugiere que tenga nada que ver con SQLGROUP BY
. Retiraré el voto negativo cuando alguien lo haya dejado claro, pero ese documento es realmente engañoso.values
, descubrí que extrañaba quevalues
funciona como un GROUP BY. Que es mi culpa. Creo que es más fácil de usaritertools.groupby
que este django-group-by cuandovalues
es insuficiente.group by
anterior con una simplevalues
llamada -con o sinannotate
y sin obtener todo de la base de datos. Su sugerencia deitertools.groupby
trabajos para pequeños conjuntos de datos, pero no para varios miles de conjuntos de datos que probablemente desee buscar. Por supuesto, en ese momento tendrá que pensar en un índice de búsqueda especial que contenga datos preparados (ya agrupados) de todos modos.El documento dice que puede usar valores para agrupar el conjunto de consultas.
Puede encontrar todos los libros y agruparlos por nombre usando este código:
Puedes ver alguna hoja de cheet aquí .
fuente
Si no me estoy equivocando, puedes usar, whatever-query-set .group_by = [' field ']
fuente
primero necesitas importar Sum y luego ...
fuente