Django: calcula la suma de los valores de la columna a través de la consulta

92

Tengo un modelo

class ItemPrice( models.Model ):
     price = models.DecimalField ( max_digits = 8, decimal_places=2 )
     ....

Intenté esto para calcular la suma de priceen este conjunto de consultas:

items = ItemPrice.objects.all().annotate(Sum('price'))

¿Qué hay de malo en esta consulta? ¿O hay alguna otra forma de calcular la suma de la pricecolumna?

Sé que esto se puede hacer usando for loop en queryset pero necesito una solución elegante.

¡Gracias!

Ahsan
fuente
¿Responde esto a tu pregunta? ¿Consulta SUM de Django?
Flimm

Respuestas:

196

Probablemente estas buscando aggregate

from django.db.models import Sum

ItemPrice.objects.aggregate(Sum('price'))
# returns {'price__sum': 1000} for example
MattH
fuente
1
¿Cómo puedo obtener un recuento total cuyo precio = 5000?
Anuj Sharma
6
Recuerde que devuelve el diccionario, no flotante / entero, por ejemplo {'price__sum':1000}. Puede obtener flotante / entero conyourdict['price__sum']
Josh
35

Anotar agrega un campo a los resultados:

>> Order.objects.annotate(total_price=Sum('price'))
<QuerySet [<Order: L-555>, <Order: L-222>]>

>> orders.first().total_price
Decimal('340.00')

Agregado devuelve un dictado con el resultado solicitado:

>> Order.objects.aggregate(total_price=Sum('price'))
{'total_price': Decimal('1260.00')}
Ibrohim Ermatov
fuente
Le agradezco que me muestre cómo especificar el keypara almacenar la suma value.
MikeyE
32

Use .aggregate(Sum('column'))['column__sum']reefer mi ejemplo a continuación

sum = Sale.objects.filter(type='Flour').aggregate(Sum('column'))['column__sum']
ugali suave
fuente
5

Usando cProfile Profiler , encuentro que en mi entorno de desarrollo, es más eficiente (más rápido) sumar los valores de una lista que agregar usando Sum(). p.ej:

sum_a = sum([item.column for item in queryset]) # Definitely takes more memory.
sum_b = queryset.aggregate(Sum('column')).get('column__sum') # Takes about 20% more time.

Probé esto en diferentes contextos y parece que usarlo aggregatesiempre lleva más tiempo para producir el mismo resultado. Aunque sospecho que podría haber ventajas en cuanto a memoria para usarlo en lugar de sumar una lista.

Tío Saam
fuente
1
También puede utilizar un generador de expresión en lugar de una lista: sum_a = sum(item.column for item in queryset). La única diferencia son los []s eliminados . Esto ahorra espacio en la memoria para calcular la lista completa antes de sum()iterar sobre ella.
Code-Apprentice