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


293

我想编写一个与此SQL查询等效的Django查询:

SELECT * from user where income >= 5000 or income is NULL.

如何构造Django queryset过滤器?

User.objects.filter(income__gte=5000, income=0)

这是行不通的,因为它AND是过滤器。我想要OR过滤器以获取单个查询集的并集。


Answers:


547
from django.db.models import Q
User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True))

通过文档


如果您添加了object.query的打印内容,这将有所帮助,这样我们就可以将ORM和Query输出相关联以使其熟悉。顺便说一句很好的例子。
Eddwin Paz

使用这种类型的查询还是执行两个单独的查询更好?
MHB

60

由于QuerySet实现了Python __or__运算符(|)或并集,因此它可以正常工作。正如您所期望的,|二进制运算符返回一个QuerySetso 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中找到


18
“无证”和“遗留”使我感到害怕。我认为使用Q对象更安全,如此处接受的答案所述。
0atman 2014年

2
FYI,order_by()和distinct()合并后可以应用于管道查询集
2014年

@carruthd谢谢。我也确认了这一点。将编辑
滚刀

是否可以将order_by()应用于每个单独的查询集,然后进行组合?这样,每个条件的顺序仍然保持不变?例如,combined_queryset = User.objects.filter(income__gte = 5000).order_by('income')| User.objects.filter(income__lt = 5000).order_by('-income')吗?
2014年

2
@Oatman:| 操作员已记录在案。请参阅docs.djangoproject.com/en/2.0/ref/models/querysets:“通常,Q()对象使定义和重用条件成为可能。这允许使用|(OR)和&( AND)运算子;特别是,否则无法在QuerySet中使用OR。” 我没有检查早期版本的文档,但是管道运算符至少在Django 1.1.4上有效(只是尝试过)。
makeroo '18

10

现有答案中已经提到了这两种选择:

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食谱在这个比较详细谈到,这里是有关部分:


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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.