2012-01-20 30 views
11

Tôi có mô hình django và một trường đại diện cho một tên đầy đủ của người dùng. Khách hàng của tôi muốn tôi thiết lập bộ lọc để tìm kiếm người dùng dựa trên một chuỗi các chuỗi nơi tất cả chúng phải phân biệt chữ hoa chữ thường trong tên đầy đủ.Lọc cơ sở dữ liệu Django cho trường có chứa bất kỳ giá trị nào trong một mảng

Ví dụ

Nếu một người dùng full_name = "Keith, Thomson S."

Và tôi có một danh sách ['keith','s','thomson']

Tôi muốn thực hiện bộ lọc tương đương với

Profile.objects.filter(full_name__icontains='keith',full_name__icontains='s',full_name__icontains='thomson') 

Vấn đề là trong danh sách này có thể kích thước động - vì vậy tôi không biết cách thực hiện điều này.

Bất kỳ ai có ý tưởng nào?

Trả lời

33

Thực hiện cuộc gọi liên tiếp để filter, như vậy:

queryset = Profile.objects.all() 
strings = ['keith', 's', 'thompson'] 
for string in strings: 
    queryset = queryset.filter(full_name__icontains=string) 

Hoặc bạn có thể & cùng một loạt các Q đối tượng:

condition = Q(full_name__icontains=s[0]) 
for string in strings[1:]: 
    condition &= Q(full_name__icontains=string) 
queryset = Profile.objects.filter(condition) 

Một cách khó hiểu hơn về văn bản này, tránh các vòng lặp rõ ràng :

import operator 
# ... 
condition = reduce(operator.and_, [Q(full_name__icontains=s) for s in strings]) 
queryset = Profile.objects.filter(condition) 
+0

Tôi tự hỏi biểu thức sql cuối cùng sẽ trông như thế nào sau khi chuỗi tất cả các bộ lọc này. – akonsu

+0

@akonsu Tôi vừa thử nó (tốt, một cái gì đó tương tự) - nó được dịch sang một chuỗi 'AND' trong mệnh đề 'where', tức là' full_name LIKE% keith% AND full_name LIKE% s% AND ... ' –

+2

@isbadawi, +1 - lưu ý rằng toán tử mặc định cho nhiều đối tượng Q là AND vì vậy bạn chỉ có thể' * [Q1, Q2, Q3] 'mà không cần sử dụng reduce/operator.and_. –

2

somethi ng dọc theo các dòng sau:


array = ['keith', 's', 'thomson'] 
regex = '^.*(%s).*$' % '|'.join(array) 
Profile.objects.filter(full_name__iregex=regex) 

EDIT: điều này sai, OP muốn tên có chứa tất cả các chuỗi cùng một lúc.

3

Thậm chí ngắn hơn bằng cách sử dụng operator chức năng and_ hoặc or_ để kết hợp danh sách các Q() điều kiện

from operator import and_, or_ 
li = ['keith', 's', 'thompson'] 

Các mặt hàng phù hợp với tất cả các chuỗi (and_)

Profile.objects.filter(reduce(and_, [Q(full_name__icontains=q) for q in li])) 

Các mặt hàng phù hợp với bất kỳ chuỗi (or_)

Profile.objects.filter(reduce(or_, [Q(full_name__icontains=q) for q in li])) 

Chức năng Q() thực hiện __or__()__and__() để ghép hai đối tượng Q() với nhau, để chúng có thể được gọi bằng cách sử dụng các chức năng operator tương ứng.

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