2011-10-11 14 views
5

Mam jeden do wielu relacji.django models sum field from foreign key relationship

class Invoice(models.Model): 
    stuff 

class Item(models.Model): 
    invoice = models.ForeignKey(Invoice) 
    qty = models.IntegerField() 
    unit_price = models.DecimalField(max_digits=4, decimal_places=2) 

Chcę, aby kwerendę, aby wybrać wszystkie wiersze w fakturze i sumę cen wszystkich elementów dla każdej faktury, a dostęp ją przez queryset

np więc jeśli invoice #1 ma 2 items, każdy z qty=2 i unit_price=3, invoice #1 musiałby amount 2x2x3 = $12

UPDATE:

Oto co mam tak daleko, ale to daje mi traceback

inv_list = \ 
Invoice.objects.select_related().all()\ 
.aggregate(sum=sum('item__unit_price')).order_by('-inv_date') 

TypeError at /site/invoice/ 
unsupported operand type(s) for +: 'int' and 'str' 

UPDATE

Dzięki za wkład, wziąłem kilka kolejek i koniec I utworzono nową kolumnę unit_amount, dodano dodatkową akcję do metody .save() do zrobienia prod_qty * unit_price i zapisania jej w nowej kolumnie.

a potem zrobił to:

inv_list = Invoice.objects.all()\ 
.annotate(amount=Sum('item__unit_amount')).order_by('-inv_date') 
+0

Czy na pewno wszystkie swoje unit_price są int w bazie danych? –

Odpowiedz

2

Jeśli nie select_related() wtedy myślę, że należy zrobić .aggregate(sum=sum('unit_price')), prawda? Wciąż select_related() wydaje się być dużo.

Również aggregate da ci słownik {sum:value}, więc zamówienie wydaje się być pomyłką? Po co to jest? Nie jestem tego pewien. :)

Jeśli to nie działa, może próbować tego trochę inaczej?

for invoice in Invoice.objects.all(): 
    tmp = invoice.item_set.aggregate(sum=sum('unit_price')) 
    # do some stuff with sum 

Ponieważ uważam, że chcesz mieć sumę za fakturę, a nie sumę globalną. Spróbuj.

// EDYCJA: Oczywiście, że zapomniałem o ilości. W takim przypadku kod podczerwieni jest lepszy.

2
for invoice in Invoice.objects.all(): 
    ammount = 0 
    for item in invoice.item_set.all(): 
     ammount += item.qty * item.unit_price 
     print invoice.pk, ammount 
2

Od F() wyrażenia were refactoredin Django 1.8 To stało się proste i jednoznaczne:

from django.db.models import F, Sum 

Invoice.objects.annotate(Sum(F('item__unit_price') * F('item__qty'))) 
Powiązane problemy