1

次のコードがある場合:

class A(models.Model):

   .....

class B(models.Model):

    a = models.ManyToManyField(A)

次のクエリは異なる結果を取得します。

B.objects.exclude(a__in=[7])

from django.db.models import Q
B.objects.exclude(Q(a__in=[7]))

結果:

  • 最初のクエリは、a=7 の「b オブジェクト」を除くすべてのオブジェクトを取得します。大丈夫です
  • しかし、2 番目のクエリは、a=7 または a=None の「b オブジェクト」を除くすべてのオブジェクトを取得します。

エラーですか?、既知ですか?

詳細な例を追加し、次のコードを実行します

from django.contrib.auth.models import User, Group
u1 = User.objects.create(username='u1')
u2 = User.objects.create(username='u2')
u3 = User.objects.create(username='u3')
g1 = Group.objects.create(name='g1')
g2 = Group.objects.create(name='g2')
u1.groups.add(g1)
u2.groups.add(g2)
print User.objects.exclude(groups__in=[g1.pk])
print User.objects.exclude(Q(groups__in=[g1.pk]))
4

2 に答える 2

2

これを「エラー」と呼ぶかどうかはわかりませんが、2 つのバージョンは一意のクエリを送信します (Django 1.3.1)。

なしQ:

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 NOT ("auth_user"."id" IN
             (SELECT U1."user_id"
              FROM "auth_user_groups" U1
              WHERE (U1."group_id" IN (2)
                     AND U1."user_id" IS NOT NULL)))

Q:

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"
INNER JOIN "auth_user_groups" ON ("auth_user"."id" = "auth_user_groups"."user_id")
WHERE NOT ("auth_user_groups"."group_id" IN (2))

興味深いのは、filter代わりにを使用するとexclude、どちらもまったく同じクエリを送信することです。とはいえ、これは実際には意図的なものかもしれません。Q単独で実際に使用されることはありません (意味がありません)。そのため、クエリは追加の AND/OR/NOT 関係に対して事前に最適化されている可能性があります。Q一方、すべての意図と目的のために、なしのバージョンが行われます。この動作に本当に問題がある場合は、チケットを提出できますが、チケットQが 1 つしかない場合は使用しないでください。

于 2012-01-27T15:42:45.723 に答える
1

現在、これは Django で修正されています。

https://code.djangoproject.com/ticket/17600

これはジャンゴのバグでした

于 2013-10-14T08:01:18.763 に答える