如何在Django queryset中执行OR条件?

435 投票
6 回答
296648 浏览
提问于 2025-04-16 20:46

我想写一个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%)'

来源: django-orm-cookbook


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

查看文档

撰写回答