簡體   English   中英

如何在 django 查詢集中執行 OR 條件?

[英]How to perform OR condition in django queryset?

我想寫一個 Django 查詢等同於這個 SQL 查詢:

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

如何構建 Django 查詢集過濾器?

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

這不起作用,因為它AND s 過濾器。 我想對過濾器進行OR操作以獲得單個查詢集的並集。

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

通過文檔

因為QuerySet 實現了 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 參考中完整記錄。 更多歷史討論可以在DjangoProject ticket #21333中找到。

現有答案中已經提到了這兩個選項:

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


如果有人可能正在尋找它,只需為附加到Q object 的多個過濾器添加這個。 如果提供了Q object,則它必須位於任何關鍵字 arguments 的定義之前。 否則它是一個無效的查詢。 做的時候你應該小心。

一個例子是

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

這里考慮了 OR 條件和具有收入類別的過濾器

為了添加我們在 sql 查詢中使用的“OR”或“AND”之類的條件,我們以這種方式為例

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

我希望您能夠正確理解“,”用於“AND”運算符和“|” 用於 django 中使用的“或”運算符。

與@lprsd 的回答類似,您可以使用operator庫中的or_

from operator import or_
from django.db.models import Q

User.objects.filter(or_(Q(income__gte=5000), Q(income__isnull=True)))

operator.or_得到兩個值 arguments。要使用三個語句(或更多)使用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)))

此解決方案可能對動態生成的查詢非常有幫助(例如,使用來自前端輸入的自定義參數)。

細節

operatorfunctools是 python 標准庫,這意味着你不需要安裝它們。

正如您在or_ function 的文檔字符串中看到的那樣,對於ab arguments,它是

與 | 相同 b.

reduce

將兩個arguments中的function累加到序列的各項中,從左到右,使序列化為單值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM