【问题标题】:How to perform OR condition in django queryset?如何在 Django 查询集中执行 OR 条件?
【发布时间】:2011-09-27 21:52:26
【问题描述】:

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

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

如何构造 Django 查询集过滤器?

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

这不起作用,因为它ANDs 过滤器。我想OR 过滤器来获得单个查询集的联合。

【问题讨论】:

标签: python sql django django-queryset django-orm


【解决方案1】:
from django.db.models import Q
User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True))

via Documentation

【讨论】:

  • 如果你添加一个 object.query 的 print 会有所帮助,这样我们就可以将 ORM 和 Query 输出联系起来以熟悉它。顺便说一句,很好的例子。
  • 是使用这种类型的查询还是执行两个单独的查询更好?
  • 如果这个@lakshman 还有其他查询怎么办
  • 如果两个查询相同,它将返回重复的查询。如何避免?
  • 我刚刚在 6 分钟后发现了如何避免重复。在查询之前使用 set() 函数。喜欢:set(User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True)))
【解决方案2】:

因为QuerySets implement 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 年 6 月 20 日更新:现在已在 Django 2.1 QuerySet API reference 中完整记录。更多历史讨论可以在DjangoProject ticket #21333找到。

【讨论】:

  • “无证”和“遗留”让我害怕。我认为使用 Q 对象更安全,如此处接受的答案中所述。
  • 仅供参考,order_by() 和 distinct() 可以在组合后应用于管道查询集
  • @Oatman: |操作员记录在案。请参阅docs.djangoproject.com/en/2.0/ref/models/querysets:“通常,Q() 对象可以定义和重用条件。这允许使用 | (OR) 和 & (AND) 运算符构造复杂的数据库查询;特别是,否则不可能在查询集中使用 OR。”我没有检查早期版本的文档,但管道运算符至少可以从 Django 1.1.4 工作(刚刚尝试过)。
  • 不,@OsmanHamashool,我认为这是个坏主意。它使用 python 的内置 set 构造函数从数据库中删除查询集的重复数据。始终在您的查询集上使用.distinct()。这将在您的数据库 (SQL) 中更有效地运行,而不会给您的 python 进程带来负担。下次使用“django queryset unique”来查找 Django 文档中的 .distinct() 方法。
  • @hobs 谢谢,使用 python 的set 还有另一个缺点,那就是你不能对你的查询集进行排序。我现在打算切换到postgres,我会再次测试并在这里更新结果。
【解决方案3】:

现有答案中已经提到了这两个选项:

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


【讨论】:

    【解决方案4】:

    只需为附加到Q 对象的多个过滤器添加它,如果有人可能正在寻找它。 如果提供了Q object,它必须在任何关键字参数的定义之前。否则它是一个无效的查询。做的时候要小心。

    一个例子是

    from django.db.models import Q
    User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True),category='income')
    

    这里考虑了 OR 条件和带有收入类别的过滤器

    【讨论】:

      猜你喜欢
      • 2015-09-25
      • 1970-01-01
      • 2018-06-18
      • 1970-01-01
      • 1970-01-01
      • 2018-11-18
      • 1970-01-01
      • 2016-06-10
      • 2010-10-18
      相关资源
      最近更新 更多