2012-08-28 13 views
30

que tiene un modelo de algo como estoDjango Agregación: La suma de la multiplicación de dos campos

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

Ahora me gustaría hacer un cálculo Sum(progress * estimated_days) en el nivel de base de datos. Usando la Agregación de Django puedo tener la suma para cada campo pero no la suma de la multiplicación de campos.

Respuesta

60

Actualización: para Django> = 1,8 siga la respuesta proporcionada por @kmmbvnr

es posible utilizar ORM de Django:

esto es lo usted debe hacer:

from django.db.models import Sum 

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

Nota: si los dos campos son de diferentes tipos, dicen integer & float, del tipo que desea devolver debe ser pasado como primer parámetro de Sum

Es una respuesta tardía, pero supongo que va a ayudar a alguien que busca lo mismo.

+1

Funciona bien, gracias, pero tenga en cuenta que el * campo * kwarg no está documentado y que no encontré ninguna prueba al respecto en el conjunto de pruebas de Django. –

+0

¡Esto es genial! Todavía funciona en django 1.7. – haudoing

+0

¿Qué hace el campo 'progreso'?Estoy tratando de descubrir este fragmento de código, ya que es exactamente lo que necesito – Maor

2

¿Tiene varias opciones:

  1. Raw query
  2. Emulbreh's undocumented approach
  3. Crear un tercer campo progress_X_estimated_days y actualizarlo en Guardar método sobreescrito. Luego haz la agregación a través de este nuevo campo.

sobrescritura:

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

Sí, en realidad estaba manteniendo el SQL crudo o un atributo adicional como el ultima opcion. Gracias de todos modos. –

35

Con Django 1.8 y por encima de usted puede pasar ahora una expresión de su agregado:

from django.db.models import F 

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

Constantes también están disponibles, y todo es combinable:

from django.db.models import Value 

Task.objects.aggregate(total=Sum('progress')/Value(10))['total'] 
+0

Creo que esta respuesta es más fácil de entender y mantener. Además, si los tipos de estos campos son diferentes, agregue el parámetro 'output_field' para agregar la función –

+4

. Esta es la respuesta correcta actual. Gracias –

+1

Lo estoy probando en django 1.7 pero estoy obteniendo AttributeError 'AttributeError: El objeto 'ExpressionNode' no tiene atributo 'split', para qué versión mi versión de django es 1.7.10 –

10

La solución depende de la versión de 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'))) 
    
Cuestiones relacionadas