找出这些差异发生原因的最佳方法是调查生成的查询:django-debug-toolbar
附带一个debugsqlshell
命令,该命令在使用 Django 查询集 API 后打印发送到数据库的实际查询。对于这些测试,我使用了User
带有 join on 的模型Group
。我也注意到所选对象的计数不同,因此从表面上看,它似乎与您的用例有很好的相关性。
User.objects.filter(~Q(username='jdoe', groups__name='Awesome Group'))
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"."username" = 'jdoe'
AND "auth_user"."id" IN
(SELECT U1."user_id"
FROM "auth_user_groups" U1
INNER JOIN "auth_group" U2 ON (U1."group_id" = U2."id")
WHERE (U2."name" = 'Awesome Group'
AND U1."user_id" IS NOT NULL))) LIMIT 21
User.objects.exclude(Q(username='jdoe', groups__name='Awesome Group'))
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")
INNER JOIN "auth_group" ON ("auth_user_groups"."group_id" = "auth_group"."id")
WHERE NOT (("auth_user"."username" = 'jdoe'
AND "auth_group"."name" = 'Awesome Group')) LIMIT 21
这里的区别在于 INNER JOIN 发生的位置。该Q
对象在第一个示例中导致 INNER JOIN,然后由于~
. 的情况下exclude
,否定与 INNER JOIN 并行发生。