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 对象”。没关系
  • 但是第二个查询获取所有对象,不包括 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

我不确定我是否会称其为“错误”,但是这两个版本确实发送了独特的查询(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如果你真的对这种行为有疑问,你可以提交一张票,但我会说当你只有一张票时不要使用。

于 2012-01-27T15:42:45.723 回答
1

现在这在 Django 中得到了修复:

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

这是一个 django 错误

于 2013-10-14T08:01:18.763 回答