Django 注释两个字段相乘的总和

Django 注释两个字段相乘的总和,django,django-models,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.Mo

我有三个模型,例如简化模型:

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).annotation(总花费=总和(F('order\u lineitem\u quantity')*F('order\u lineitem\u price'))


Sum()似乎不能与F()表达式一起使用。还有其他方法可以做到这一点吗?

您看过使用
.extra()
方法吗


请参阅。

您可以尝试使用
行项目中的属性
模型:

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 ...")
Customer.objects.raw(“从何处选择…”)

我刚刚遇到了这个问题,我不认为该注释可以用于属性,请参见

这就是我所做的

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和列表理解:

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

您可能需要推出自己的自定义聚合器。您可以在这里找到一个简单的
GROUP\u CONCAT
示例,让您从这里开始:

类似于:


编辑:感谢@Max,使用注释代替聚合。

也许您现在不需要这个答案,但是如果您阅读了关于的文档,您需要声明
输出\u字段,如下所示:

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

是的。它可以工作,但我试图避免它,原因有两个:第一,它使用每行子查询而不是联接,这可能会对某些数据库后端造成严重的扩展。第二,它不适用于filter()在额外的字段上,因此它不能与其他Q对象按程序组合。你能做到这一点吗?我正在寻找一个解决方案,它的可能重复项不起作用,因为属性是在查询后计算的。这个选项起作用,但你用python而不是sql进行求和,这意味着随着它变大,速度会慢很多。我没有ried这个,它不起作用,我得到
无法将关键字解析到字段中的
错误:-(好的,从另一个答案上的注释来看,这似乎无法通过属性上的注释来完成。Django ORM生成通过SQL执行计算的查询,因此,不可能将Python定义的属性作为查询的一部分包含在方法中。您可以应用列表理解post查询,但这不同事情,正如Justin Hamade所指出的。你用了正确的方法:但不是聚合使用注释,而是在结果中删除['total']:total=Task.objects.filter(这里是你的过滤器)。注释(total=Sum('progress',field=“progress*estimated_days”)。重新制作一个积极的例子
Customer.objects.filter(something)
                .annotate(total_spent=Sum(
                    F('order__lineitem__quantity') * 
                    F('order__lineitem__price'),   
                    output_field=models.FloatField()
                ))