61

我有一个这样的模型:

class Task(models.Model):
    progress = models.PositiveIntegerField()
    estimated_days = models.PositiveIntegerField()

现在我想Sum(progress * estimated_days)在数据库级别进行计算。使用 Django Aggregation 我可以得到每个字段的总和,但不能得到字段乘法的总和。

4

4 回答 4

93

使用 Django 1.8 及更高版本,您现在可以将表达式传递给您的聚合:

 from django.db.models import F

 Task.objects.aggregate(total=Sum(F('progress') * F('estimated_days')))['total']

常量也可用,一切都可以组合:

 from django.db.models import Value

 Task.objects.aggregate(total=Sum('progress') / Value(10))['total']
于 2015-06-22T12:09:19.990 回答
76

更新:对于Django >= 1.8,请遵循@kmmbvnr 提供的答案

可以使用 Django ORM:

这是你应该做的:

from django.db.models import Sum

total = ( Task.objects
            .filter(your-filter-here)
            .aggregate(
                total=Sum('progress', field="progress*estimated_days")
             )['total']
         )

注意:如果两个字段的类型不同,比如integer& float,你要返回的类型应该作为第一个参数传递Sum

这是一个迟到的答案,但我想它会帮助寻找相同的人。

于 2013-11-10T09:22:50.847 回答
36

解决方案取决于 Django 版本。

  • django < 1.8

    from django.db.models import Sum
    MyModel.objects.filter(<filters>).aggregate(Sum('field1', field="field1*field2"))
    
  • django >= 1.8

    from django.db.models import Sum, F
    MyModel.objects.filter(<filters>).aggregate(Sum(F('field1')*F('field2')))
    
于 2016-03-15T23:19:19.893 回答
2

已编辑(在 Django 1.8 之后)

从 Django 1.8 开始,您可以使用F

from django.db.models import F. Sum

total = ( 
    Task
    .objects
    .aggregate(total=Sum(F('progress') * F('estimated_days'))) 
    ['total']
)

旧答案(在 Django 1.8 之前)

这个答案是在 2012 年写的,django 1.8 是在 2015 年发布的

你有几个选择:

  1. 原始查询
  2. Emulbreh 的无证方法
  3. 创建第三个字段progress_X_estimated_days并在 save overwrited 方法中对其进行更新。然后通过这个新字段进行聚合。

覆盖:

class Task(models.Model):
   progress = models.PositiveIntegerField()
   estimated_days = models.PositiveIntegerField()
   progress_X_estimated_days = models.PositiveIntegerField(editable=False)

   def save(self, *args, **kwargs):
      progress_X_estimated_days = self.progress * self.estimated_days
      super(Task, self).save(*args, **kwargs)
于 2012-08-28T21:17:12.147 回答