最近在过滤器中发现了一些奇特的东西,我无法相信它的预期行为。
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")))
然后这会返回我期望的结果(空列表)。
对我来说似乎是个错误,或者我错过了什么?
史蒂夫
答案 0 :(得分:1)
以下是为两者生成的查询:
<强> User.objects.filter(id__in = User.objects.none()。values_list( “ID”,平= 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”,平= 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
。
我强调了那一部分,因为我确定你现在正在上下跳,但是none
应该返回一个空的查询集。是的,但它是通过自动返回EmptyQuerySet
并且从不实际查询数据库来实现的。它不会向查询添加任何过滤器。
这是否是一个错误是值得商榷的。我更倾向于把它称为边缘情况,很可能不会真正“修复”。它是在这一场景中所有交织部分如何组合在一起的函数。