Django: calcula a soma dos valores da coluna por meio de consulta

98

Eu tenho uma modelo

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

Tentei calcular a soma de priceneste queryset:

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

o que há de errado nesta consulta? ou existe alguma outra maneira de calcular a soma da pricecoluna?

Eu sei que isso pode ser feito usando o loop for no queryset, mas preciso de uma solução elegante.

Obrigado!

Ahsan
fonte
Isso responde sua pergunta? Django SUM Query?
Flimm

Respostas:

202

Você provavelmente está procurando por aggregate

from django.db.models import Sum

ItemPrice.objects.aggregate(Sum('price'))
# returns {'price__sum': 1000} for example
MattH
fonte
1
Como posso obter a contagem total cujo preço = 5000?
Anuj Sharma
6
Lembre-se de retornar o dicionário, não float / inteiro, por exemplo {'price__sum':1000}. Pode obter float / inteiro comyourdict['price__sum']
Josh
37

Annotate adiciona um campo aos resultados:

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

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

O agregado retorna um dict com o resultado solicitado:

>> Order.objects.aggregate(total_price=Sum('price'))
{'total_price': Decimal('1260.00')}
Ibrohim Ermatov
fonte
Agradeço por ter mostrado como especificar o keyno qual armazenar a soma value.
MikeyE
35

Use .aggregate(Sum('column'))['column__sum']reefer meu exemplo abaixo

sum = Sale.objects.filter(type='Flour').aggregate(Sum('column'))['column__sum']
ugali macio
fonte
Estou recebendo um erro: objeto 'decimal.Decimal' não é iterável
Roni X
5

Usando o criador de perfil cProfile , descobri que, em meu ambiente de desenvolvimento, é mais eficiente (mais rápido) somar os valores de uma lista do que agregar usando Sum(). por exemplo:

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.

Eu testei isso em diferentes contextos e parece que o uso aggregateleva sempre mais tempo para produzir o mesmo resultado. Embora eu suspeite que pode haver vantagens em termos de memória para usá-lo em vez de somar uma lista.

UncleSaam
fonte
3
Como alternativa, use um gerador de expressão em vez de uma lista: sum_a = sum(item.column for item in queryset). A única diferença são os []s removidos . Isso economiza espaço de memória para calcular a lista inteira antes de sum()iterar sobre ela.
Code-Apprentice
obtendo um erro: objeto 'decimal.Decimal' não é iterável
Roni X