如何在Django queryset中执行OR条件?
我想写一个Django查询,跟这个SQL查询一样:
SELECT * from user where income >= 5000 or income is NULL.
我该怎么构建Django的查询集过滤器呢?
User.objects.filter(income__gte=5000, income=0)
这样做不行,因为它是把过滤条件用AND
连接起来的。我想用OR
连接过滤条件,这样才能得到各个查询集的并集。
6 个回答
31
这两种选择在之前的回答中已经提到过了:
from django.db.models import Q
q1 = User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True))
还有
q2 = User.objects.filter(income__gte=5000) | User.objects.filter(income__isnull=True)
不过,似乎大家对选择哪一个有些困惑。
关键是它们在SQL层面上是一样的,所以你可以随意选择你喜欢的!
Django ORM Cookbook对此进行了详细讨论,这里是相关部分:
queryset = User.objects.filter(
first_name__startswith='R'
) | User.objects.filter(
last_name__startswith='D'
)
会导致
In [5]: str(queryset.query)
Out[5]: 'SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login",
"auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name",
"auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff",
"auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user"
WHERE ("auth_user"."first_name"::text LIKE R% OR "auth_user"."last_name"::text LIKE D%)'
还有
qs = User.objects.filter(Q(first_name__startswith='R') | Q(last_name__startswith='D'))
会导致
In [9]: str(qs.query)
Out[9]: 'SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login",
"auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name",
"auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff",
"auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user"
WHERE ("auth_user"."first_name"::text LIKE R% OR "auth_user"."last_name"::text LIKE D%)'
84
因为 QuerySets 实现了 Python 的 __or__
操作符(|
),也就是并集,所以它可以正常工作。正如你所期待的,|
这个二元操作符会返回一个 QuerySet
,因此你可以在后面继续使用 order_by()
、.distinct()
以及其他的查询过滤器。
combined_queryset = User.objects.filter(income__gte=5000) | User.objects.filter(income__isnull=True)
ordered_queryset = combined_queryset.order_by('-income')
更新于2019-06-20:这在 Django 2.1 QuerySet API 参考文档 中已经有了完整的说明。更多历史讨论可以在 DjangoProject 票据 #21333 中找到。
797
from django.db.models import Q
User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True))