7

最近、フィルターに奇妙なものが見つかりました。その意図した動作が信じられません。

from django.contrib.auth.models import User
print User.objects.filter(id__in=User.objects.none().values_list("id",flat=True))
print User.objects.filter(id__in=User.objects.all().values_list("id",flat=True))

奇妙なことに、これらのリストは両方ともユーザーの完全なセットを返します。内部クエリをリスト関数でラップすると、実際には「修正」するのはかなり簡単なようです。

User.objects.filter(id__in=list(User.objects.none().values_list("id")))

次に、これは私が期待するもの(空のリスト)を返します。

私にはバグのように思えますか、それとも何か不足していますか?

スティーブ

4

1 に答える 1

2

両方に対して作成されたクエリは次のとおりです。

User.objects.filter(id__in=User.objects.none().values_list("id",flat=True))

SELECT "auth_user"."id",
       "auth_user"."username",
       "auth_user"."first_name",
       "auth_user"."last_name",
       "auth_user"."email",
       "auth_user"."password",
       "auth_user"."is_staff",
       "auth_user"."is_active",
       "auth_user"."is_superuser",
       "auth_user"."last_login",
       "auth_user"."date_joined"
FROM "auth_user"
WHERE "auth_user"."id" IN
    (SELECT U0."id"
     FROM "auth_user" U0) LIMIT 21

User.objects.filter(id__in=User.objects.all().values_list("id",flat=True))

SELECT "auth_user"."id",
       "auth_user"."username",
       "auth_user"."first_name",
       "auth_user"."last_name",
       "auth_user"."email",
       "auth_user"."password",
       "auth_user"."is_staff",
       "auth_user"."is_active",
       "auth_user"."is_superuser",
       "auth_user"."last_login",
       "auth_user"."date_joined"
FROM "auth_user"
WHERE "auth_user"."id" IN
    (SELECT U0."id"
     FROM "auth_user" U0) LIMIT 21

何か気づきましたか?それらはまったく同じクエリです。User.objects.none()、 、User.objects.filter(id__in=[])などを試してみるとどうなるかも興味深いですUser.objects.filter(id__in=User.objects.none()。これら 3 つの状況すべてで、Django はクエリをショートサーキットします。つまり、データベースにクエリを発行することさえありません。結果がないと事前に判断されているからです。ここでの私の最善の推測はvalues_list、最後に追加すると短絡ロジックが無効になり、実際のクエリを送信できるようになり、実際に送信values_listする必要があるクエリを決定することです。あなたがそれについて考えるとき、どちらの場合も実際には同じです。idいずれにせよ、フィルタリングされていないクエリセットだけを選択したい場合。

私はその部分を強調しました。なぜなら、あなたは今言っていると思いますがnone、空のクエリセットを返す必要があるからです。確かにそうですが、自動的に を返し、EmptyQuerySet実際にはデータベースにまったくクエリを実行しないためです。クエリにフィルターを追加しません。

これがバグかどうかは議論の余地があります。私はこれを、実際には「修正」できない可能性が最も高いエッジケースと呼ぶ傾向があります。これは、この 1 つのシナリオですべての織り交ぜられた部分がどのように組み合わされるかの関数です。

于 2012-07-20T16:29:09.943 に答える