Làm thế nào để thực hiện điều kiện OR trong bộ truy vấn django?


294

Tôi muốn viết một truy vấn Django tương đương với truy vấn SQL này:

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

Làm thế nào để xây dựng bộ lọc truy vấn Django?

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

Điều này không hoạt động, bởi vì nó ANDlà các bộ lọc. Tôi muốn ORcác bộ lọc để có được sự kết hợp của các truy vấn cá nhân.


Câu trả lời:


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

thông qua Tài liệu


Sẽ rất hữu ích nếu bạn thêm một bản in của object.query để chúng tôi có thể liên kết cả đầu ra ORM và Truy vấn để làm quen với nó. Ví dụ tuyệt vời của BTW.
Eddwin Paz

Là tốt hơn để sử dụng loại truy vấn này hoặc thực hiện hai truy vấn riêng biệt?
MHB

60

QuerySets triển__or__ khai toán tử Python ( |) hoặc union, nên nó chỉ hoạt động. Như bạn mong muốn, các |nhà điều hành nhị phân trả về một QuerySetquá order_by(), .distinct()và bộ lọc queryset khác có thể được tacked trên đến cùng.

combined_queryset = User.objects.filter(income__gte=5000) | User.objects.filter(income__isnull=True)
ordered_queryset = combined_queryset.order_by('-income')

Cập nhật 2019-06-20: Điều này hiện đã được ghi lại đầy đủ trong tài liệu tham khảo API Django 2.1 Queryset . Nhiều cuộc thảo luận lịch sử có thể được tìm thấy trong vé DjangoProject # 21333 .


18
"Không có giấy tờ" và "di sản" làm tôi sợ hãi. Tôi nghĩ an toàn hơn khi sử dụng đối tượng Q, như chi tiết trong câu trả lời được chấp nhận ở đây.
0atman

2
FYI, order_by () và
differ

@carruthd cảm ơn. Tôi đã xác nhận điều này là tốt. Sẽ chỉnh sửa
hobs

Order_by () có thể được áp dụng cho từng bộ truy vấn riêng lẻ và sau đó kết hợp không? Vì vậy, thứ tự cho từng điều kiện vẫn được duy trì? Ví dụ: kết hợp_queryset = User.objects.filter (thu nhập__gte = 5000) .order_by ('thu nhập') | User.objects.filter (thu nhập__lt = 5000) .order_by ('- thu nhập')?
bế tắc

2
@Oatman: | toán tử được ghi lại. Xem docs.djangoproject.com/en/2.0/ref/models/querysets : "Nói chung, các đối tượng Q () cho phép xác định và sử dụng lại các điều kiện. Điều này cho phép xây dựng các truy vấn cơ sở dữ liệu phức tạp bằng cách sử dụng | (OR) và & ( Các toán tử AND), đặc biệt, không thể sử dụng OR trong QuerySets. " Tôi đã không kiểm tra tài liệu cho các phiên bản trước nhưng nhà điều hành đường ống hoạt động từ Django 1.1.4 ít nhất (chỉ cần thử).
sản xuất

10

Cả hai tùy chọn đã được đề cập trong các câu trả lời hiện có:

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)

Tuy nhiên, dường như có một số nhầm lẫn về việc nên chọn cái nào hơn.

Vấn đề là chúng giống hệt nhau ở cấp độ SQL , vì vậy hãy thoải mái chọn bất cứ thứ gì bạn thích!

Các Django ORM Cookbook nói một cách chi tiết về vấn đề này, đây là phần có liên quan:


queryset = User.objects.filter(
        first_name__startswith='R'
    ) | User.objects.filter(
    last_name__startswith='D'
)

dẫn đến

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

dẫn đến

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

nguồn: django-orm-cookbook


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.