導入
「合計金額」「平均点」「A または B」。一覧を出すだけでなく、数字を集計したり、複雑な条件で絞ったりしたくなります。ORM はそれもこなします。
説明
import django
from django.conf import settings
if not settings.configured:
settings.configure(DEBUG=True, SECRET_KEY="dev", INSTALLED_APPS=[],
DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}})
django.setup()
from django.db import models, connection
from django.db.models import Sum, Avg, Max, Min, Q
class Sale(models.Model):
item = models.CharField(max_length=50)
price = models.IntegerField()
category = models.CharField(max_length=20)
class Meta:
app_label = "shop"
with connection.schema_editor() as schema:
schema.create_model(Sale)
for item, price, cat in [("りんご", 150, "果物"), ("牛乳", 200, "飲料"),
("みかん", 100, "果物"), ("お茶", 130, "飲料")]:
Sale.objects.create(item=item, price=price, category=cat)
# 集計:合計・平均・最大(aggregate は辞書で返る)
print(Sale.objects.aggregate(Sum("price"), Avg("price"), Max("price")))
# 件数
print("果物の件数:", Sale.objects.filter(category="果物").count())
# OR 条件:category が果物 「または」 price が 180 以上
q = Sale.objects.filter(Q(category="果物") | Q(price__gte=180))
print("果物 or 180円以上:", [s.item for s in q])
# AND / NOT も Q で書ける: 飲料 かつ 150円未満ではない
q2 = Sale.objects.filter(Q(category="飲料") & ~Q(price__lt=150))
print("飲料 かつ 150円以上:", [s.item for s in q2])
aggregate(Sum("price"))… 合計。Avg・Max・Min・Countも同様。結果は{"price__sum": 580}のような辞書。- 通常の
filter(a=1, b=2)は AND(両方満たす)。 - OR や NOT を書きたいときは Q オブジェクトを使います。
|が OR、&が AND、~が NOT。
やってみよう
aggregate に Min("price") を足す、Q(...) の条件を変えるなどして、集計結果と絞り込み結果の変化を確かめましょう。
演習
Q を使って「category が飲料 または item が りんご」のレコードを絞り込み、その item のリストを表示してください。出力に りんご と 牛乳 が含まれれば成功です。
ヒント1を見る
Sale.objects.filter(Q(category="飲料") | Q(item="りんご"))。
ヒント2を見る
print([s.item for s in q])。