sku、キット、kit_contents、およびチェックリストのスキーマを含むデータベースがあります。以下は、「チェックリスト 1 で定義されたキット レコードに対して定義された kitcontent レコードに対して定義されたすべての SKU を教えてください」のクエリです。
SELECT DISTINCT s.* FROM skus s
JOIN kit_contents kc ON kc.sku_id = s.id
JOIN kits k ON k.id = kc.kit_id
JOIN checklists c ON k.checklist_id = 1;
私は Django を使用していますが、そのクエリを次のように表現できるため、ORM が非常に気に入っています。
skus = SKU.objects.filter(kitcontent__kit__checklist_id=1).distinct()
これは、これらすべての外部キーをナビゲートする非常に巧妙な方法です。Django の ORM は、基本的に上記の SQL と同じものを生成します。問題は、チェックリスト 1 で定義されていないすべての SKU を取得する方法が明確でないことです。上記の SQL クエリでは、「=」を「!=」に置き換えてこれを行います。しかし、Django のモデルには不等号演算子がありません。exclude() メソッドを使用することになっていますが、これは次のようになります。
skus = SKU.objects.filter().exclude(kitcontent__kit__checklist_id=1).distinct()
しかし、Django は次のクエリを生成しますが、これは同じものではありません。
SELECT distinct s.* FROM skus s
WHERE NOT ((skus.id IN
(SELECT kc.sku_id FROM kit_contents kc
INNER JOIN kits k ON (kc.kit_id = k.id)
WHERE (k.checklist_id = 1 AND kc.sku_id IS NOT NULL))
AND skus.id IS NOT NULL))
(読みやすく比較しやすいように、クエリをクリーンアップしました。)
私は Django ORM の初心者で、可能であれば使用したいと考えています。ここで欲しいものを手に入れる方法はありますか?
編集:
karthikr は、元の ORM .exclude() ソリューションが機能しないのと同じ理由で機能しないという回答を出しました。投稿を開いた手動クエリを使用すると、「checklist_id = 1」を使用すると 34 件の結果が生成され、「checklist_id = 2」を使用すると 53 件の結果が生成され、次のクエリでは 26 件の結果が生成されます。
SELECT DISTINCT s.* FROM skus s
JOIN kit_contents kc ON kc.sku_id = s.id
JOIN kits k ON k.id = kc.kit_id
JOIN checklists c ON k.checklist_id = 1
JOIN kit_contents kc2 ON kc2.sku_id = s.id
JOIN kits k2 ON k2.id = kc2.kit_id
JOIN checklists c2 ON k2.checklist_id = 2;
これが、人々が .exclude() ソリューションをある種の not_equals フィルターの合理的な代替物と見なしていないように見える理由の 1 つだと思います。おそらく前者もクエリを表現できるようにすることができますが、そのようなソリューションが単純であることにますます絶望しています。