список значений в EmptyQuerySet, используемый в фильтре queryset, возвращает полный набор

недавно нашел что-то особенное в фильтре, я не могу поверить в его предполагаемое поведение.

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

затем он возвращает то, что я ожидал (пустой список).

Кажется мне ошибкой, или я что-то пропустил?

Стив

1 ответов


вот запросы как:

пользователей.объекты.фильтр (id__in=пользователь.объекты.никто.)(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

пользователей.объекты.фильтр (id__in=пользователь.объекты.все.)(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(). Во всех трех из них обстоятельства, Django короткое замыкание запроса. Другими словами, он даже не выдает запрос в базу данных, поскольку заранее определяет, что результатов не будет. Мое лучшее предположение здесь, что добавление values_list до конца побеждает логику короткого замыкания, позволяя отправлять фактический запрос, и это на самом деле values_list что определяет запрос, который должен быть отправлен. Что в обоих случаях действительно одно и то же, если подумать. В любом случае вы хотите выбрать только id на Ан нефильтрованное объект QuerySet.

я подчеркнул эту часть, потому что я уверен, что вы прыгаете вверх и вниз, говоря, но none должен возвращать пустой queryset. Верно, но это происходит благодаря автоматическому возврату EmptyQuerySet и вообще никогда не запрашивал базу данных. Он не добавляет никаких фильтров в запрос.

является ли это ошибкой или нет, спорно. Я более склонен называть это крайним случаем, который, скорее всего, не может быть "исправлен". Это функция того, как все переплетающиеся части объединяются в этом одном сценарии.