2009-04-11 43 views
201

Làm cách nào để thực hiện "hoặc" trong bộ lọc django.Bộ lọc Django - hoặc?

Về cơ bản, tôi muốn để có thể liệt kê các mục mà một trong hai người dùng đã được thêm vào (chúng được liệt kê như là tác giả) hoặc các mục đã được phê duyệt

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

item.creator = owner or item.moderated = False 

Làm cách nào để thực hiện điều này trong django (tốt nhất là với bộ lọc/truy vấn)

Trả lời

361

Có các đối tượng cho phép tra cứu phức tạp. Ví dụ:

from django.db.models import Q 

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

cách điều này có thể được thực hiện theo chương trình không? Vì vậy, ví dụ có thể có 'cho f trong bộ lọc: Item.objects.filter (Q (tác giả = f1) | Q (tác giả = f2) | ...)' – Alexis

+10

@AlexisK Sử dụng một cái gì đó như 'giảm ​​(lambda q , f: q | Q (tác giả = f), bộ lọc, Q()) 'để tạo đối tượng Q lớn. – Phob

+16

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

82

Bạn có thể sử dụng | nhà điều hành để kết hợp queryset trực tiếp mà không cần đối tượng Q:

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

(chỉnh sửa - Tôi đã bước đầu không chắc chắn nếu điều này gây ra một truy vấn phụ trợ nhưng @spookylukey chỉ ra rằng đánh giá queryset lười biếng chăm sóc đó)

+4

Để tìm ra truy vấn nào được thực hiện trên một yêu cầu đã cho, bạn có thể sử dụng thanh công cụ gỡ lỗi Ứng dụng Django. Nó được làm bằng tuyệt vời và giành chiến thắng. –

+0

Tôi đã thử nghiệm này từ vỏ. Có cách nào để theo dõi các truy vấn cho các dòng trên trực tiếp từ vỏ? –

+21

do 'từ kết nối nhập khẩu django.db' và sử dụng 'connection.queries'. Điều này yêu cầu DEBUG = True. BTW, bạn nên biết rằng [QuerySets là lười biếng] (https://docs.djangoproject.com/en/dev/topics/db/queries/#querysets-are-lazy) và điều này lượt truy cập DB chỉ một lần. – spookylukey

16

Bạn muốn để làm cho bộ lọc động sau đó 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]) | ..... 
+4

Câu trả lời hoàn hảo cho tôi! Đối với python3, làm 'từ functools nhập khẩu giảm' trước. – Dharmit

10

Tương tự như answera già đi, nhưng một chút đơn giản hơn, nếu không có sự lambda:

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

Để lọc hai điều kiện 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ự cách lập trình:

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

(được chia thành hai dòng ở đây, để rõ ràng)

operator có trong thư viện tiêu chuẩn: import operator
Từ docstring:

or_ (a, b) - Tương tự như a | b.

Đối Python3, giảm không có trong thư viện chuẩn: from functools import reduce


T.B.

Đừng quên đảm bảo list_of_Q không trống - reduce() sẽ bị nghẹn trên danh sách trống, cần ít nhất một phần tử.

9

Điều đáng lưu ý là nó có thể để thêm Q biểu thức.

Ví dụ:

from django.db.models import Q 

query = Q(first_name='mark') 
query.add(Q(email='[email protected]'), Q.OR) 
query.add(Q(last_name='doe'), Q.AND) 

queryset = Users.objects.filter(query) 

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

(first_name = 'mark' or email = '[email protected]') and last_name = 'doe' 

Bằng cách này không có nhu cầu để đối phó với hoặc nhà khai thác, giảm của, vv

Các vấn đề liên quan