だから私はこれに相当するモデルを持っています(非常に単純化されています、明らかに):
class Mystery(models.Model):
name = models.CharField(max_length=100)
class Character(models.Model):
mystery = models.ForeignKey(Mystery, related_name="characters")
required = models.BooleanField(default=True)
基本的に、各ミステリーには、ストーリーに不可欠であるかどうかに関係なく、多くのキャラクターがいます。ミステリーを上演できる俳優の最小数は、そのミステリーに必要なキャラクターの数です。最大数はミステリーの合計文字数です。
今、私は特定の数の俳優が演じることができる謎を探そうとしています。Djangoのフィルタリングおよび注釈機能が機能する方法を使用すると、それは十分に簡単に思えました。結局のところ、これらのクエリは両方とも正常に機能します。
# Returns mystery objects with at least x characters in all
Mystery.objects.annotate(max_actors=Count('characters', distinct=True)).filter(max_actors__gte=x)
# Returns mystery objects with no more than x required characters
Mystery.objects.filter(characters__required=True).annotate(min_actors=Count('characters', distinct=True)).filter(min_actors__lte=x)
しかし、私が2つを組み合わせようとすると...
Mystery.objects.annotate(max_actors=Count('characters', distinct=True)).filter(characters__required=True).annotate(min_actors=Count('characters', distinct=True)).filter(min_actors__lte=x, max_actors__gte=x)
...動作しません。min_actorsとmax_actorsの両方に、最大数のアクターが含まれています。実行されている実際のクエリの関連部分は次のようになります。
SELECT `mysteries_mystery`.`id`,
`mysteries_mystery`.`name`,
COUNT(DISTINCT `mysteries_character`.`id`) AS `max_actors`,
COUNT(DISTINCT `mysteries_character`.`id`) AS `min_actors`
FROM `mysteries_mystery`
LEFT OUTER JOIN `mysteries_character` ON (`mysteries_mystery`.`id` = `mysteries_character`.`mystery_id`)
INNER JOIN `mysteries_character` T5 ON (`mysteries_mystery`.`id` = T5.`mystery_id`)
WHERE T5.`required` = True
GROUP BY `mysteries_mystery`.`id`, `mysteries_mystery`.`name`
...これにより、Djangoが文字テーブルに2番目の結合を正常に作成している間(テーブルの2番目のコピーはT5にエイリアスされています)、そのテーブルは実際にはどこでも使用されておらず、両方のカウントが使用されていることがわかります非エイリアスバージョンから選択されます。これにより、どちらの場合も明らかに同じ結果が得られます。
句を使用しextra
てT5から選択しようとしても、出力クエリを調べると2番目の文字テーブルがT5にエイリアシングしていることがわかっているにもかかわらず、T5のようなテーブルはないと言われます。extra
句を使用してこれを行う別の試みは、次のようになりました。
Mystery.objects.annotate(max_actors=Count('characters', distinct=True)).extra(select={'min_actors': "SELECT COUNT(*) FROM mysteries_character WHERE required = True AND mystery_id = mysteries_mystery.id"}).extra(where=["`min_actors` <= %s", "`max_actors` >= %s"], params=[x, x])
しかし、少なくともMySQLでは、WHERE句で計算フィールドを使用できないため、これは機能しませんでした。HAVINGを使用できたとしても、残念ながら、Djangoの.extra()では、 HAVINGパラメーターを設定できません。
DjangoのORMに私がやりたいことをさせる方法はありますか?