widgets tutorial formularios form fields example django django-aggregation

formularios - django tutorial



Django: Agrupar por fecha(día, mes, año) (5)

Tengo un modelo simple como este:

class Order(models.Model): created = model.DateTimeField(auto_now_add=True) total = models.IntegerField() # monetary value

Y quiero mostrar un desglose mes a mes de:

  • Cuántas ventas hubo en un mes ( COUNT )
  • El valor combinado ( SUM )

No estoy seguro de cuál es la mejor manera de atacar esto. He visto algunas consultas extra-selectas de aspecto bastante aterrador, pero mi mente simple me dice que podría estar mejor simplemente iterando números, comenzando desde un año / mes de inicio arbitrario y contando hasta llegar al mes actual, descartando simples consultas de filtrado para ese mes. Más trabajo en la base de datos, ¡menos estrés para el desarrollador!

¿Qué tiene más sentido para ti? ¿Hay alguna buena manera de que pueda extraer una tabla rápida de datos? ¿O es mi método sucio probablemente la mejor idea?

Estoy usando Django 1.3. No estoy seguro de si han agregado una forma más agradable de GROUP_BY recientemente.


Aquí está mi sucio método. Está sucio.

import datetime, decimal from django.db.models import Count, Sum from account.models import Order d = [] # arbitrary starting dates year = 2011 month = 12 cyear = datetime.date.today().year cmonth = datetime.date.today().month while year <= cyear: while (year < cyear and month <= 12) or (year == cyear and month <= cmonth): sales = Order.objects.filter(created__year=year, created__month=month).aggregate(Count(''total''), Sum(''total'')) d.append({ ''year'': year, ''month'': month, ''sales'': sales[''total__count''] or 0, ''value'': decimal.Decimal(sales[''total__sum''] or 0), }) month += 1 month = 1 year += 1

Puede que haya una mejor forma de repetir años / meses, pero eso no es realmente lo que me importa :)


Otro enfoque es usar ExtractMonth . Tuve problemas al usar TruncMonth debido a que solo se devolvió un valor de fecha y hora del año. Por ejemplo, solo se devolvieron los meses de 2009. ExtractMonth solucionó este problema perfectamente y se puede utilizar de la siguiente manera:

from django.db.models.functions import ExtractMonth Sales.objects .annotate(month=ExtractMonth(''timestamp'')) .values(''month'') .annotate(count=Count(''id'')) .values(''month'', ''count'')


Solo una pequeña adición a @tback answer: No funcionó para mí con Django 1.10.6 y postgres. Añadí order_by () al final para arreglarlo.

from django.db.models.functions import TruncMonth Sales.objects .annotate(month=TruncMonth(''timestamp'')) # Truncate to month and add to select list .values(''month'') # Group By month .annotate(c=Count(''id'')) # Select the count of the grouping .order_by()


Django 1.10 y superior

La documentación de Django enumera como obsoleto pronto . (Gracias por señalar eso @seddonym, @ Lucas03). Abrí un ticket y esta es la solución que proporcionó jarshwah.

from django.db.models.functions import TruncMonth Sales.objects .annotate(month=TruncMonth(''timestamp'')) # Truncate to month and add to select list .values(''month'') # Group By month .annotate(c=Count(''id'')) # Select the count of the grouping .values(''month'', ''c'') # (might be redundant, haven''t tested) select month and count

versiones anteriores

from django.db import connection from django.db.models import Sum, Count truncate_date = connection.ops.date_trunc_sql(''month'', ''created'') qs = Order.objects.extra({''month'':truncate_date}) report = qs.values(''month'').annotate(Sum(''total''), Count(''pk'')).order_by(''month'')

Edits

  • Recuento agregado
  • Información adicional para django> = 1.10

Por mes:

Order.objects.filter().extra({''month'':"Extract(month from created)"}).values_list(''month'').annotate(Count(''id''))

Por año:

Order.objects.filter().extra({''year'':"Extract(year from created)"}).values_list(''year'').annotate(Count(''id''))

Por día:

Order.objects.filter().extra({''day'':"Extract(day from created)"}).values_list(''day'').annotate(Count(''id''))

No te olvides de importar el conteo

from django.db.models import *

Para django <1.10