注释两个字段的总和相乘

时间:2009-04-30 17:46:47

标签: django django-models

我有三个模型,简化了示例:

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

看起来Sum()不能与F()表达式一起使用。还有另一种方法吗?

6 个答案:

答案 0 :(得分:9)

也许您现在不需要这个答案,但如果您阅读有关Sum expression的文档,则需要声明output_field,如下所示:

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

答案 1 :(得分:1)

您是否考虑过使用.extra()方法?

请参阅Django QuerySet API

答案 2 :(得分: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 ...")

答案 3 :(得分:1)

您可能需要推出自己的自定义聚合器。您可以在这里找到一个简单的GROUP_CONCAT示例,它可以帮助您从这里开始: http://harkablog.com/inside-the-django-orm-aggregates.html

答案 4 :(得分:0)

我刚刚遇到这个并且我认为没有注释并且会使用属性,请参阅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和list comprehension:

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

答案 5 :(得分: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,使用注释而不是聚合。

相关问题