Reputation: 1814
I've data like below. Need to get total value by calculating price - discount%
and sum of all. How to use aggregate here
models.py
class Order(TimeStamp):
code = models.CharField(max_length=255, null=True, blank=True)
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE, null=True, blank=True, related_name='order_item')
name = models.CharField(max_length=255, null=True, blank=True)
discount = models.FloatField(null=True, blank=True)
price = models.FloatField(null=True, blank=True)
def __str__(self):
return self.name
Upvotes: 0
Views: 619
Reputation: 477814
You can calculate the discounted price for each item through .annotate(…)
[Django-doc]:
from django.db.models import F, Sum
OrderItem.objects.annotate(
total=F('price') * 0.01 * (100-F('discount'))
)['total']
If you want to sum up the discounted prices, we can use a Sum
expression [Django-doc]:
from django.db.models import F, Sum
OrderItem.objects.aggregate(
total_price=Sum(F('price') * 0.01 * (100-F('discount')))
)['total_price']
or for a specific order:
from django.db.models import F, Sum
myorder.order_item.aggregate(
total_price=Sum(F('price') * 0.01 * (100-F('discount')))
)['total_price']
You likely want to do this per Order
object:
from django.db.models import F, Sum
Order.objects.annotate(
total_price=Sum(F('order_item__price') * 0.01 * (100-F('order_item__discount')))
)
The Order
objects that arise from this will have an extra attribute .total_price
that contains the total price.
Note: I would refrain from making a lot (all) fields
NULL
-able. It means that if fields areNULL
, expressions and aggregates with these fields can beNULL
as well, and often are if one of the included fields isNULL
. OftenNULL
-able fields are rare, and used if it is valid to have missing information.
Note: The
related_name=…
[Django-doc] is the name of the manager to fetch the related objects in reverse. Therefore normally therelated_name
of aForeignKey
orManyToManyField
is plural, for exampleorder_items
instead of.order_item
Note: It might make more sense to work with a
DecimalField
[Django-doc] than with aFloatField
[Django-doc]], since a decimal has fixed precision, and less rounding errors, Especially when working with financial data, that is more accurate.
Upvotes: 2