Làm cách nào để thực hiện bộ lọc OR trong truy vấn Django?


303

Tôi muốn có thể liệt kê các mục mà người dùng đã thêm (chúng được liệt kê là người tạo) hoặc mục đã được phê duyệt.

Vì vậy, về cơ bản tôi cần phải chọn:

item.creator = owner or item.moderated = False

Làm thế nào tôi có thể làm điều này trong Django? (tốt nhất là với bộ lọc hoặc bộ truy vấn).

Câu trả lời:


544

Có những Qđối tượng cho phép tra cứu phức tạp. Thí dụ:

from django.db.models import Q

Item.objects.filter(Q(creator=owner) | Q(moderated=False))

6
Làm thế nào điều này có thể được thực hiện theo chương trình? Vì vậy, ví dụ có thể cófor f in filters: Item.objects.filter(Q(creator=f1) | Q(creator=f2) | ...)
Alexis

14
@AlexisK Sử dụng một cái gì đó như reduce(lambda q, f: q | Q(creator=f), filters, Q())để tạo đối tượng Q lớn.
Phob

24
@alexis: bạn cũng có thể làm Item.objects.filter(creator__in=creators), ví dụ.
Kevin London

4
Nếu bạn tự hỏi (như tôi) nơi |được sử dụng làm toán tử OR đến từ đâu, thì đó thực sự là toán tử hợp nhất đã đặt. Nó cũng được sử dụng (không phải ở đây) như bitwise OR: stackoverflow.com/questions/5988665/pipe-character-in-python
e100

124

Bạn có thể sử dụng | toán tử để kết hợp các truy vấn trực tiếp mà không cần các đối tượng Q:

result = Item.objects.filter(item.creator = owner) | Item.objects.filter(item.moderated = False)

(chỉnh sửa - Ban đầu tôi không chắc chắn nếu điều này gây ra một truy vấn bổ sung nhưng @spookylukey đã chỉ ra rằng việc đánh giá bộ truy vấn lười biếng quan tâm đến điều đó)


4
Để tìm ra những truy vấn nào được thực hiện theo một yêu cầu nhất định, bạn có thể sử dụng ứng dụng Django gỡ lỗi. Nó được làm từ tuyệt vời và giành chiến thắng.
Deniz Dogan

25
làm 'từ django.db nhập kết nối' và sử dụng 'Connection.queries'. Điều này đòi hỏi DEBUG = True. BTW, bạn nên biết rằng QuerySets lười biếng và điều này đánh vào DB chỉ một lần.
spookylukey

1
Có thể loại trừ được sử dụng với so sánh phủ định?
Neob91

2
điều này có thể dẫn đến trùng lặp trong bộ truy vấn kết quả không?
Charles Haro

1
Các bộ truy vấn cụ thể hơn có xu hướng chỉ đánh DB khi bạn cố gắng lập chỉ mục cho chúng, nếu không, bạn chỉ đang xây dựng một truy vấn.
awiebe

41

Cần lưu ý rằng có thể thêm biểu thức Q.

Ví dụ:

from django.db.models import Q

query = Q(first_name='mark')
query.add(Q(email='mark@test.com'), Q.OR)
query.add(Q(last_name='doe'), Q.AND)

queryset = User.objects.filter(query)

Điều này kết thúc với một truy vấn như:

(first_name = 'mark' or email = 'mark@test.com') and last_name = 'doe'

Bằng cách này, không cần phải đối phó với hoặc điều hành, giảm vv.


2
Nhưng nó dễ viết hơn query |= Q(email='mark@test.com')?
Alex78191

26

Bạn muốn làm cho bộ lọc động thì bạn phải sử dụng Lambda như

from django.db.models import Q

brands = ['ABC','DEF' , 'GHI']

queryset = Product.objects.filter(reduce(lambda x, y: x | y, [Q(brand=item) for item in brands]))

reduce(lambda x, y: x | y, [Q(brand=item) for item in brands]) tương đương với

Q(brand=brands[0]) | Q(brand=brands[1]) | Q(brand=brands[2]) | .....

6
Câu trả lời hoàn hảo cho tôi! Đối với python3, làm from functools import reducetrước.
Dharmit

1
Tại sao không sử dụng operator.or_thay thế lambda x, y: x | y?
Alex78191

20

Tương tự như answerera cũ, nhưng đơn giản hơn một chút, không có lambda:

filter_kwargs = {
    'field_a': 123,
    'field_b__in': (3, 4, 5, ),
}

Để lọc hai điều kiện này bằng cách sử dụng OR:

Item.objects.filter(Q(field_a=123) | Q(field_b__in=(3, 4, 5, ))

Để có được kết quả tương tự theo chương trình:

list_of_Q = [Q(**{key: val}) for key, val in filter_kwargs.items()]
Item.objects.filter(reduce(operator.or_, list_of_Q))

(chia thành hai dòng ở đây, cho rõ ràng)

operatornằm trong thư viện chuẩn: import operator
Từ doc Chuỗi:

or_ (a, b) - Giống như a | b.

Đối với Python3, reducekhông còn là phần dựng sẵn nữa mà vẫn nằm trong thư viện chuẩn:from functools import reduce


PS

Đừng quên đảm bảo list_of_Qkhông trống - reduce()sẽ bị nghẹt trong danh sách trống, nó cần ít nhất một yếu tố.


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.