query example documentacion decimalfield django django-models

django - example - Anotar una suma de dos campos multiplicados



django models select (6)

Tengo tres modelos, simplificados para el ejemplo:

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)

Quiero consultar a los clientes (posiblemente con un filtro) y anotar el total que han gastado (es decir, la suma total (precio * cantidad)

Yo he tratado:
Customer.objects.filter(something).annotate(total_spent=Sum(F(''order__lineitem__quantity'') * F(''order__lineitem__price'')))

Parece que Sum () no se puede usar con expresiones F (). Hay otra manera de hacer esto?



Me acabo de topar con esto y no creo que anotar y trabajar con una propiedad, ver Django - ¿Se puede usar la propiedad como el campo en una función de agregación?

Aquí esta lo que hice.

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

Luego use la suma y una lista de comprensión:

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


Podría intentar usar una propiedad en el modelo LineItem :

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)

Entonces creo que puedes hacer anotaciones con la cantidad total gastada usando

Customer.objects.filter(something).annotate(total_spent=Sum(''order__lineitem__total''))

No sé cómo se relaciona la eficiencia de este método con otros, pero es más Pythonic / Django-y que la alternativa, que es escribir toda la consulta SQL a mano como en

Customer.objects.raw("SELECT ... from <customer_table_name> where ...")



Similar a: https://.com/a/19888120/1344647

from django.db.models import Sum q = Task.objects.filter(your-filter-here).annotate(total=Sum(''progress'', field="progress*estimated_days"))

Editado: Gracias a @Max, utilizando anotaciones en su lugar agregadas.


Tal vez no necesite esta respuesta ahora, pero si lee la documentación sobre la expresión Suma , necesita declarar el campo output_field , así:

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