我想写一个Django查询等价于下面的SQL查询:
SELECT * from user where income >= 5000 or income is NULL.
如何构造Django queryset过滤器?
User.objects.filter(income__gte=5000, income=0)
这行不通,因为它和过滤器。我想对过滤器进行OR操作以获得单个查询集的并集。
我想写一个Django查询等价于下面的SQL查询:
SELECT * from user where income >= 5000 or income is NULL.
如何构造Django queryset过滤器?
User.objects.filter(income__gte=5000, income=0)
这行不通,因为它和过滤器。我想对过滤器进行OR操作以获得单个查询集的并集。
当前回答
类似于@lprsd的答案,你可以使用or_ from操作符库:
from operator import or_
from django.db.models import Q
User.objects.filter(or_(Q(income__gte=5000), Q(income__isnull=True)))
操作符。Or_得到两个值作为参数。要使用三个(或更多)语句,请使用reduce:
from operator import or_
from functools import reduce
from django.db.models import Q
User.objects.filter(reduce(or_, Q(income__gte=5000), Q(income__lt=300), Q(income__isnull=True)))
这种解决方案对于动态生成的查询(例如,使用前端输入的自定义参数)非常有用。
细节
Operator和functools是python标准库,这意味着你不需要安装它们。
正如你在or_函数的文档字符串中看到的,对于a和b参数,它是
和|b一样。
和减少:
将两个参数的函数累加到序列项上, 从左到右,从而将序列简化为单个值。
其他回答
为了添加像“OR”或“AND”这样的条件,就像我们在sql查询中使用的那样,我们有这样的方法作为示例
from django.db.models import Q
Poll.objects.get(Q(question__startswith='Who'),Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
这相当于这个SQL查询
SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
我希望你能够正确地理解,“,”是“与”操作符,而“|”是django中使用的“或”操作符。
现有的答案中已经提到了这两个选项:
from django.db.models import Q
q1 = User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True))
and
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%)'
and
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
因为QuerySets实现了Python __or__操作符(|)或联合,所以它可以工作。正如您所期望的那样,|二进制操作符返回一个QuerySet,因此order_by()、.distinct()和其他QuerySet过滤器可以附加到末尾。
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中找到。
只是添加这个附加到Q对象的多个过滤器,如果有人可能会寻找它。 如果提供了Q对象,它必须在任何关键字参数的定义之前。否则它是一个无效的查询。你做这件事的时候要小心。
一个例子是
from django.db.models import Q
User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True),category='income')
这里考虑了OR条件和带有收入类别的过滤器
from django.db.models import Q
User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True))
通过文档