DjangoのORMでQuerySet全体の集計(合計、平均、最大値、最小値、件数など)を行うには、aggregate()メソッドを使用します。annotate()が各レコードに値を追加するのに対し、aggregate()はQuerySet全体を1つの値にまとめます。
基本的な使い方
views.py
from django.db.models import Avg
# 全商品の平均価格を取得
avg_price = Product.objects.aggregate(Avg('price'))
説明
Step 1Aggregate関数の基本
Djangoのaggregate()メソッドは、クエリセット全体に対して集計を行い、辞書型で結果を返します。これまで紹介したannotate()がクエリセットの各オブジェクトに集計フィールドを追加するのに対し、aggregate()はクエリセット全体に対して単一の集計値を返します。
from django.db.models import Avg, Max, Min, Sum, Count
# 基本的な使い方
result = モデル名.objects.aggregate(集計関数('フィールド名'))
Step 2基本的な使用例
例えば、Productモデルの全商品の平均価格を取得する場合:
from django.db.models import Avg
# 全商品の平均価格を取得
avg_price = Product.objects.aggregate(Avg('price'))
# 結果: {'price__avg': 1234.56}
返り値は辞書型で、キーはデフォルトで「フィールド名__集計関数」という形式になります。
Step 3複数の集計を同時に行う
複数の集計を一度のクエリで行うことも可能です:
from django.db.models import Avg, Max, Min, Sum, Count
# 複数の集計を一度に行う
result = Product.objects.aggregate(
avg_price=Avg('price'),
max_price=Max('price'),
min_price=Min('price'),
total_inventory=Sum('stock'),
product_count=Count('id')
)
# 結果: {'avg_price': 1234.56, 'max_price': 9999.99, 'min_price': 10.0, 'total_inventory': 1500, 'product_count': 100}
このように、キーワード引数を使用することで、結果の辞書のキー名をカスタマイズできます。
Step 4条件付き集計
フィルタリングと組み合わせて、条件に一致するレコードだけを集計することもできます:
# アクティブな商品の平均価格
active_avg = Product.objects.filter(is_active=True).aggregate(
active_avg_price=Avg('price')
)
# カテゴリー別の商品数
from django.db.models import Count
category_counts = Product.objects.values('category').annotate(
count=Count('id')
).order_by('-count')
# 複数条件を組み合わせた集計
from django.db.models import Q
result = Product.objects.filter(
Q(category='Electronics') | Q(category='Computers')
).aggregate(
avg_price=Avg('price'),
total_stock=Sum('stock')
)
Step 5関連モデルの集計
関連するモデルのフィールドに対しても集計を行えます:
# 全顧客の注文合計金額
from django.db.models import Sum
total_sales = Customer.objects.aggregate(
total_order_amount=Sum('order__amount')
)
# 各商品の総売上(annotateを使用)
product_sales = Product.objects.annotate(
total_sales=Sum('orderitem__quantity * orderitem__price')
).aggregate(
grand_total=Sum('total_sales')
)
Step 6実践的な使用例
views.pyでのAggregate関数の使用例:
from django.shortcuts import render
from django.db.models import Avg, Sum, Min, Max, Count
from .models import Product, Order, Customer
def dashboard(request):
# 商品統計
product_stats = Product.objects.aggregate(
total_products=Count('id'),
avg_price=Avg('price'),
max_price=Max('price'),
min_price=Min('price'),
total_stock=Sum('stock')
)
# 売上統計
sales_stats = Order.objects.aggregate(
total_orders=Count('id'),
total_revenue=Sum('total_amount'),
avg_order_value=Avg('total_amount'),
max_order=Max('total_amount')
)
# カテゴリー別商品数
category_stats = Product.objects.values('category').annotate(
count=Count('id'),
avg_category_price=Avg('price')
).order_by('-count')
# アクティブか非アクティブかで分けた商品数
status_counts = {
'active': Product.objects.filter(is_active=True).count(),
'inactive': Product.objects.filter(is_active=False).count()
}
return render(request, 'dashboard.html', {
'product_stats': product_stats,
'sales_stats': sales_stats,
'category_stats': category_stats,
'status_counts': status_counts
})
テンプレートでの使用例(dashboard.html):
<h1>ダッシュボード</h1>
<div class="stats-card">
<h2>商品統計</h2>
<p>総商品数: {{ product_stats.total_products }}点</p>
<p>平均価格: {{ product_stats.avg_price|floatformat:0 }}円</p>
<p>最高価格: {{ product_stats.max_price|floatformat:0 }}円</p>
<p>最低価格: {{ product_stats.min_price|floatformat:0 }}円</p>
<p>在庫総数: {{ product_stats.total_stock }}個</p>
</div>
<div class="stats-card">
<h2>売上統計</h2>
<p>総注文数: {{ sales_stats.total_orders }}件</p>
<p>総売上: {{ sales_stats.total_revenue|floatformat:0 }}円</p>
<p>平均注文額: {{ sales_stats.avg_order_value|floatformat:0 }}円</p>
<p>最高注文額: {{ sales_stats.max_order|floatformat:0 }}円</p>
</div>
<div class="stats-card">
<h2>カテゴリー別商品数</h2>
<table>
<tr>
<th>カテゴリー</th>
<th>商品数</th>
<th>平均価格</th>
</tr>
{% for category in category_stats %}
<tr>
<td>{{ category.category }}</td>
<td>{{ category.count }}点</td>
<td>{{ category.avg_category_price|floatformat:0 }}円</td>
</tr>
{% endfor %}
</table>
</div>
重要ポイント:
aggregate()はクエリセット全体に対する単一の結果を返し、辞書型で返されます。- 複数の集計を一度に行うことができ、キーワード引数を使って結果のキー名をカスタマイズできます。
- 集計関数には
Avg、Count、Max、Min、Sumなどがあります。 filter()と組み合わせることで、条件に一致するレコードだけを集計できます。- 複雑な集計では、
annotate()で中間計算を行ってからaggregate()を使用するパターンも有効です。
まとめ
aggregate()はQuerySet全体の集計結果を辞書形式で返すSum,Avg,Max,Min,Countなどの集計関数が使える- 複数の集計を1回のクエリで同時に実行できる
filter()と組み合わせて条件付きの集計が可能annotate()との違いは、QuerySet全体を1つの辞書にまとめる点- 戻り値はQuerySetではなく辞書(dict)なので、チェーンはできない