Django: calculer la somme des valeurs de colonne via une requête

92

J'ai un modèle

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

J'ai essayé ceci pour calculer la somme de pricedans cet ensemble de requêtes:

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

quel est le problème dans cette requête? ou y a-t-il un autre moyen de calculer la somme de la pricecolonne?

Je sais que cela peut être fait en utilisant la boucle for sur le jeu de requêtes, mais j'ai besoin d'une solution élégante.

Merci!

Ahsan
la source
Est-ce que cela répond à votre question? Requête Django SUM?
Flimm

Réponses:

196

Vous recherchez probablement aggregate

from django.db.models import Sum

ItemPrice.objects.aggregate(Sum('price'))
# returns {'price__sum': 1000} for example
MattH
la source
1
Comment puis-je obtenir le nombre total dont le prix = 5000?
Anuj Sharma
6
Rappelez-vous que renvoie le dictionnaire non flottant / entier, par exemple {'price__sum':1000}. Peut obtenir un flottant / un entier avecyourdict['price__sum']
Josh
35

Annoter ajoute un champ aux résultats:

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

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

Aggregate renvoie un dict avec le résultat demandé:

>> Order.objects.aggregate(total_price=Sum('price'))
{'total_price': Decimal('1260.00')}
Ibrohim Ermatov
la source
Je vous remercie de montrer comment spécifier le keydans lequel stocker la somme value.
MikeyE
32

Utilisez .aggregate(Sum('column'))['column__sum']reefer mon exemple ci-dessous

sum = Sale.objects.filter(type='Flour').aggregate(Sum('column'))['column__sum']
ugali doux
la source
5

En utilisant le profileur cProfile , je trouve que dans mon environnement de développement, il est plus efficace (plus rapide) de faire la somme des valeurs d'une liste que d'agréger en utilisant Sum(). par exemple:

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.

J'ai testé cela dans différents contextes et il semble que l'utilisation aggregateprenne toujours plus de temps pour produire le même résultat. Bien que je soupçonne qu'il pourrait y avoir des avantages en termes de mémoire à l'utiliser au lieu de résumer une liste.

OncleSaam
la source
1
Vous pouvez également utiliser une expression de générateur au lieu d'une liste: sum_a = sum(item.column for item in queryset). La seule différence est que l' []art. Cela économise de l'espace mémoire pour le calcul de la liste entière avant de l' sum()itérer.
Code-Apprentice