2009-04-30 52 views
32

我有三種模式,簡化的例子:註釋兩個字段的總和乘以

class Customer(models.Model): 
    email = models.CharField(max_length=128) 

class Order(models.Model): 
    customer = models.ForeignKey(Customer) 
    order_status = models.CharField(blank=True, max_length=256) 

class Lineitem(models.Model): 
    order = models.ForeignKey(Order) 
    quantity = models.IntegerField(blank=True) 
    price = models.DecimalField(max_digits=6, decimal_places=2) 

我要查詢的客戶(可能帶有過濾器)和註釋他們所花費的總(即,在(價格*數量)的總和

我曾嘗試:?
Customer.objects.filter(something).annotate(total_spent=Sum(F('order__lineitem__quantity') * F('order__lineitem__price')))

這樣看來,點心()不能與F()表達式中使用,是否有另一種方式做到這一點

+0

你有沒有得到這個工作? – dotty 2010-06-01 15:03:01

+0

我正在尋找解決方案 – Don 2011-06-10 15:37:26

+0

[Django Aggregation:兩個字段乘法求和]的可能重複(http://stackoverflow.com/questions/12165636/django-aggregation-summation-of-multiplication-of-two場) – Louis 2016-06-27 10:43:29

回答

1

你看過使用.extra()方法嗎?

查看Django QuerySet API

+3

我有。它的工作原理,但我試圖避免它有兩個原因:首先,它使用每行子查詢,而不是聯接,這可能會嚴重縮小某些數據庫後端。其次,它不能與額外字段上的filter()一起工作,所以它不能與其他Q對象進行程序合併 – Sam 2009-04-30 19:12:52

1

你可以嘗試在LineItem模型使用屬性:

class Lineitem(models.Model): 
    order = models.ForeignKey(Order) 
    quantity = models.IntegerField(blank=True) 
    price = models.DecimalField(max_digits=6, decimal_places=2) 
    def _get_total(self): 
     return quantity * price 
    total = property(_get_total) 

那麼我認爲你可以用總量標註使用

Customer.objects.filter(something).annotate(total_spent=Sum('order__lineitem__total')) 

花我不知道怎麼的效率此方法與其他方法相關,但它比替代方法更Pythonic/Django-y,它是用手寫出整個SQL查詢,如

Customer.objects.raw("SELECT ... from <customer_table_name> where ...") 
+0

我試過這個,它不工作,我得到'Can not resolve keyword into字段錯誤。 :-( – 2012-05-19 08:18:51

1

我剛碰到這個,我不認爲這個註釋和將與一個屬性,見Django - Can you use property as the field in an aggregation function?

這是我做了什麼。

class Customer(models.Model): 
    email = models.CharField(max_length=128) 

class Order(models.Model): 
    customer = models.ForeignKey(Customer) 
    order_status = models.CharField(blank=True, max_length=256) 

class Lineitem(models.Model): 
    order = models.ForeignKey(Order) 
    quantity = models.IntegerField(blank=True) 
    price = models.DecimalField(max_digits=6, decimal_places=2) 
    @property 
    def total(self): 
     return self.quantity * self.price 

然後用總和與列表理解:

sum([li.total for li in LineItem.objects.filter(order__customer=some_customer).filter(somefilter)]) 
0

類似:https://stackoverflow.com/a/19888120/1344647

from django.db.models import Sum 

q = Task.objects.filter(your-filter-here).annotate(total=Sum('progress', field="progress*estimated_days")) 

編輯:感謝@Max,使用註釋,而不是聚合。

6

也許你現在不需要這個答案,但如果你閱讀文檔有關Sum expression,你需要聲明output_field,就像這樣:

Customer.objects.filter(something) 
       .annotate(total_spent=Sum(
        F('order__lineitem__quantity') * 
        F('order__lineitem__price'), 
        output_field=models.FloatField() 
       ))