2012-08-28 86 views
30

的乘法的总和我有一个模型,这样Django的聚合:两个字段

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

有些事情现在我希望做一个计算Sum(progress * estimated_days)在数据库级别上。使用Django聚合我可以有每个领域的总和,但不是领域乘法的总和。

回答

60

更新:的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

这是一个迟到的回答第一个参数传递的类型,但我想它会帮助寻找相同的人。

+1

工作得很好,谢谢,但要注意* field * kwarg没有记录,并且我没有在Django测试套件中找到任何关于它的测试。 –

+0

这很酷!它仍然在django 1.7上工作。 – haudoing

+0

“进度”字段的成就是什么?我试图找出这段代码片段,因为它是完全我需要的 – Maor

2

你有几种选择:

  1. Raw query
  2. Emulbreh's undocumented approach
  3. 创建第三场progress_X_estimated_days和更新它保存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) 
+0

是的,我实际上保持原始SQL或附加的属性作为最后的选择。不管怎么说,多谢拉。 –

35

使用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'] 
+0

我认为这个答案更容易理解和维护。除了这些字段的类型不同之外,将'output_field'参数添加到聚合函数 –

+4

这是当前的正确答案。谢谢 –

+1

我试图在Django的1.7,但我越来越AttributeError'AttributeError:'ExpressionNode'对象没有属性'split'',为什么版本我的django版本是1.7.10 –

10

的解决方案取决于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')))