118 votes

Django : Calculer la somme des valeurs d'une colonne par le biais d'une requête

J'ai un modèle

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

J'ai essayé de calculer la somme de price dans ce queryset :

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

qu'est-ce qui ne va pas dans cette requête ? ou existe-t-il un autre moyen de calculer la somme de price colonne ?

Je sais que cela peut être fait en utilisant une boucle for sur le queryset mais j'ai besoin d'une solution élégante.

Merci !

0 votes

Cela répond-il à votre question ? Requête SUM de Django ?

243voto

MattH Points 15352

Vous recherchez probablement aggregate

from django.db.models import Sum

ItemPrice.objects.aggregate(Sum('price'))
# returns {'price__sum': 1000} for example

1 votes

Comment puis-je obtenir le nombre total dont le prix = 5000 ?

9 votes

Rappelez-vous que les retours sont des dictionnaires et non des flottants ou des nombres entiers. {'price__sum':1000} . On peut obtenir une valeur flottante/un nombre entier avec yourdict['price__sum']

46voto

ugali soft Points 899

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

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

1 votes

Je reçois une erreur : l'objet 'decimal.Decimal' n'est pas itérable.

42voto

Ibrohim Ermatov Points 1028

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 retourne un dict avec le résultat demandé :

>> Order.objects.aggregate(total_price=Sum('price'))
{'total_price': Decimal('1260.00')}

0 votes

J'apprécie que vous montriez comment spécifier le key pour stocker la somme value dans.

8voto

UncleSaam Points 156

Utilisation de cProfile profileur Dans mon environnement de développement, je trouve qu'il est plus efficace (plus rapide) d'additionner les valeurs d'une liste que d'agréger en utilisant la méthode de l'agrégation. Sum() . eg :

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é ceci dans différents contextes et il semble que l'utilisation de aggregate prend toujours plus de temps pour produire le même résultat. Bien que je pense qu'il pourrait y avoir des avantages en termes de mémoire à l'utiliser au lieu d'additionner une liste.

4 votes

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 la suppression [] s. Cela permet d'économiser l'espace mémoire nécessaire au calcul de la liste entière avant que l'opération ne soit terminée. sum() itère sur elle.

0 votes

Obtention d'une erreur : l'objet 'decimal.Decimal' n'est pas itérable.

2voto

Jcc.Sanabria Points 149

Les réponses précédentes sont assez bien, aussi, vous pouvez obtenir ce total avec une ligne de code vanille...

items = ItemPrice.objects.all()
total_price = sum(items.values_list('price', flat=True))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X