Ошибка в инкапсулирующих фильтрах (Q) - PullRequest
1 голос
/ 26 января 2012

Если у меня есть следующий код:

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]))

Результаты:

  • Первый запрос получитьвсе объекты, кроме "b объектов" с a = 7.Это нормально
  • Но во втором запросе все объекты, кроме "b объектов", получают с a = 7 или a = None.

Это ошибка? Известно ли это?

Я добавляю подробный пример, выполняю следующий код

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]))

Ответы [ 2 ]

2 голосов
/ 27 января 2012

Я не уверен, что назвал бы это «ошибкой», но две версии посылают уникальные запросы (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 никогда не используется сам по себе (в этом нет никакого смысла), поэтому запрос, вероятно, предварительно оптимизирован для дополнительных отношений И / ИЛИ / НЕ. Принимая во внимание, что версия без Q сделана, для всех намерений и целей. Если у вас действительно есть проблемы с этим поведением, вы можете подать заявку, но я бы сказал, просто не используйте Q, когда у вас есть только один.

1 голос
/ 14 октября 2013

Теперь это исправлено в Django:

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

Это была ошибка Django

...