Django Aggregate vs Annotate with example
Django’s aggregate
and annotate
functions are used to perform calculations on querysets. While they might seem like similar, they serve different purposes. Here’s a tutorial with examples to illustrate their use.
Aggregate
The aggregate
function is used to perform a calculation on a queryset and return a dictionary of the computed values. It is generally used for overall summary operations.
Example:
Suppose you have a model called Order
:
# models.py
from django.db import models
class Order(models.Model):
customer = models.CharField(max_length=100)
amount = models.DecimalField(max_digits=10, decimal_places=2)
date = models.DateField()
You can use aggregate
to get the total amount of all orders:
# views.py or shell
from django.db.models import Sum
from .models import Order
total_amount = Order.objects.aggregate(Sum('amount'))
print(total_amount) # {'amount__sum': Decimal('Total Amount')}
This will be return dictionary with key amount__sum
containing the sum of all amount
fields in the Order
model.
Annotate
The annotate
function is used to calculate values for each item in a queryset. This is typically used for per-item calculations rather than overall summaries.
Example:
Continuing with the Order
model, suppose you have another model called Customer
:
# models.py
from django.db import models
class Customer(models.Model):
name = models.CharField(max_length=100)
To get the total amount of orders per customer, you can use annotate
:
# views.py or shell
from django.db.models import Sum
from .models import Customer, Order
customers_with_order_totals = Customer.objects.annotate(total_amount=Sum('order__amount'))
for customer in customers_with_order_totals:
print(customer.name, customer.total_amount)
This will add a total_amount
attribute to each Customer
instance, containing the sum of the amount
of all their orders.
Comparison
Aggregate: Used for overall summaries.
- Returns a single dictionary with calculated values.
- Example:
Order.objects.aggregate(Sum('amount'))
Annotate: Used for per-item calculations.
- Returns a queryset where each item has the calculated values as additional attributes.
- Example:
Customer.objects.annotate(total_amount=Sum('order__amount'))
Practical Example
Consider a model Product
and Sales
:
# models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
class Sales(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.IntegerField()
date = models.DateField()
Aggregate Example: Total Sales Quantity
# views.py or shell
from django.db.models import Sum
from .models import Sales
total_sales_quantity = Sales.objects.aggregate(total_quantity=Sum('quantity'))
print(total_sales_quantity) # {'total_quantity': Total Quantity}
Annotate Example: Total Sales Quantity per Product
# views.py or shell
from .models import Product
products_with_sales_totals = Product.objects.annotate(total_quantity=Sum('sales__quantity'))
for product in products_with_sales_totals:
print(product.name, product.total_quantity)
This will add a total_quantity
attribute to each Product
instance, showing the total quantity sold for each product.
Summary
- Use
aggregate
for overall calculations like totals, averages, etc., and get a single summary result. - Use
annotate
for per-item calculations to add computed values as attributes to each item in the queryset.