0

私は2つのモデル、Productを持っています。これは、RatingEntryと1対多の関係にあります。

>>> product_entries = models.Products.objects.all()
>>> annotated = product_entries.annotate(Count("ratingentry"))
>>> len(annotated)
210
>>> a = annotated.filter(ratingentry__count__lte = 10)
>>> b = annotated.filter(ratingentry__count__gt = 10)
>>> len(a)
10
>>> len(b)
200
>>> len(a | b)
10 //should be 210

aとbをリストに変更し、それらを連結すると、長さは210になります。

ここで何が起こっているのか分かりますか?

4

2 に答える 2

2

この動作は、Djangoのオブジェクト関係マッピングのバグだと思います。Djangoがクエリ用に生成するSQLを見ると、次のようなものが表示されます。

>>> q1 = (Products.objects.annotate(num_ratings = Count('ratingentries'))
...       .filter(num_ratings__gt = 10))
>>> q2 = (Products.objects.annotate(num_ratings = Count('ratingentries'))
...       .exclude(num_ratings__gt = 10))
>>> print(str((q1 | q2).query))
SELECT `myapp_products`.`id`, COUNT(`myapp_ratingentries`.`id`) AS
`num_ratings` FROM `myapp_products` LEFT OUTER JOIN `myapp_ratingentries` ON
(`myapp_products`.`id` = `myapp_ratingentries`.`product_id`) GROUP BY
`myapp_products`.`id` HAVING COUNT(`myapp_ratingentries`.`id`) > 10
ORDER BY NULL

fromの条件はクエリの句にq1含まれていますが、fromの条件は失われていることに注意してください。HAVINGq2

次のようにクエリを作成することで、問題を回避できます。

>>> q = Q(num_products__gt = 10) | ~Q(num_products__gt = 10)
>>> q3 = Products.objects.annotate(num_ratings = Count('ratingentries')).filter(q)
>>> print(str(q3.query))
SELECT `myapp_products`.`id`, COUNT(`myapp_ratingentries`.`id`) AS
`num_ratings` FROM `myapp_products` LEFT OUTER JOIN `myapp_ratingentries` ON
(`myapp_products`.`id` = `myapp_ratingentries`.`product_id`) GROUP BY
`myapp_products`.`id` HAVING (COUNT(`myapp_ratingentries`.`id`) > 10 OR NOT
(COUNT(`myapp_ratingentries`.`id`) > 10 )) ORDER BY NULL

両方の条件がHAVING句に含まれていることに注意してください。

これをバグとしてDjango開発者に報告することをお勧めします。(修正できない場合は、少なくとも文書化する必要があります。)

于 2012-09-27T23:26:16.527 に答える
-1

クエリセットはビット単位の包含をサポートしていません。エラーを発生させる代わりに、Djangoはそれを論理ORとして扱い、を評価する最初のものを返しますTrue。どちらも有効なクエリセットであるため、最初のクエリセットが常に返されます。

2つのクエリセットを実際に組み合わせたい場合は、それらをリストに変換してから一方を他方で拡張するか、itertools.chainのようなものを使用する必要がありますが、最終的には何にも使用できないジェネレーターになります。しかし、反復。いずれにせよ、クエリセットを組み合わせると、それらのクエリセットに対するそれ以上の操作は許可されなくなります。

于 2012-09-27T20:06:30.160 に答える