[Django / python] 関連テーブルの複数の属性を条件にしてgroup_byする(ORMで)


やりたいこと

  • 複数のテーブルを結合し、その結果できた表に対してGROUP_BYSUMを適用したい。
  • GROUP_BYの条件とするのは、関連テーブル側に存在するカラム。

どういうこと?

以下のようなテーブルがあると考えます。

テーブル

1. Orders(注文)

カラム名
id integer
date date

2. Items(商品)

カラム名
id integer
name string

3. OrderedItems(注文された商品)

カラム名
id integer
order_id integer
item_id integer
count integer

このようなテーブルがあるとして、それぞれの日(date)にどの商品(name)がどれだけ(count)注文されたのかを集計したい。

そこで次のようなSQLが思い浮かぶ....

SQL

※このSQLは実際に実行したわけではないので、このSQLには誤りが含まれている可能性がかなり高いです。
あくまでもイメージです。

SQLのイメージ
SELECT orders.date,
       items.name,
       SUM(ordered_items.count) AS total
FROM ordered_items
    LEFT JOIN orders ON ordered_items.order_id = orders.id
    LEFT JOIN items ON ordered_items.item_id = items.id
GROUP BY orders.date, items.name;

こんな感じのSQLをDjangoのORM経由で実行したい。

これでできた 1

python
from django.db.models import Sum

OrderedItem.objects \
    .values('order__date', 'item__name') \
    .annotate(total=Sum('count'))

ポイント?

どうやら、

  • GROUP_BYしたいとき
    valuesメソッドの引数に、GROUP_BYする際の条件とするカラム名を文字列で指定する
  • 他のテーブルのカラムを条件にしてGROUP_BYしたい場合
    valuesに指定するカラム名の前に、{テーブル名}__をつける
    => '{テーブル名}__{カラム名}'のようになる
  • 複数条件でGROUP_BYしたい場合
    valuesメソッドの引数として、それらの条件を全て列挙する

で良さそう。

感想

このあたりの情報をはっきりと記載している記事がなかなか見つからなかった、、、

特にポイントの3つ目については、記載されている記事を見つけられず、仕方なく勧で書いたらたまたま動いてしまった、という状況でした...ԅ(º﹃ºԅ)

そんなわけでメモ化。
(次回スムーズに同じことができる自信がない...)

参考にした記事

より役に立ったと感じた順に記載しています

そしてなぜDjangoの公式サイトがヒットしない......?
公式サイトが全然頼りにならない...


  1. 実際には、もっとわけのわからない名前のテーブルに対してこの処理実行しており、今回はわかりやすくするためにテーブル名やカラム名を変えているので、完全にこの通りに書いても動かない可能性もあります。