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!


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

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')}

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']

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.


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.