web-dev-qa-db-fra.com

Django Agrégation: sommation de la multiplication de deux champs

J'ai un modèle quelque chose comme ça

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

Maintenant, je voudrais faire un calcul Sum(progress * estimated_days) au niveau de la base de données. En utilisant Django Aggregation je peux avoir la somme pour chaque champ mais pas la somme de la multiplication des champs.

46
Raunak Agarwal

Mise à jour: pour Django> = 1.8 veuillez suivre la réponse fournie par @kmmbvnr

c'est possible en utilisant Django ORM:

voici ce que vous devez faire:

from Django.db.models import Sum

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

Remarque: si les deux champs sont de types différents, par exemple integer & float, le type que vous souhaitez renvoyer doit être passé comme premier paramètre de Sum

C'est une réponse tardive, mais je suppose que cela aidera quelqu'un à chercher la même chose.

69
sha256

Avec Django 1.8 et supérieur, vous pouvez maintenant passer une expression à votre agrégat:

 from Django.db.models import F

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

Des constantes sont également disponibles, et tout est combinable:

 from Django.db.models import Value

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

La solution dépend de la version 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')))
    
24
Antstud

Avez-vous plusieurs options:

  1. requête brute
  2. approche non documentée d'Emulbreh
  3. Créez un troisième champ progress_X_estimated_days et le mettre à jour en sauvegardant la méthode écrasée. Faites ensuite l'agrégation à travers ce nouveau champ.

Écrasement:

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)
2
dani herrera