2012-01-20 10 views
11

Mam model django i pole reprezentujące pełną nazwę użytkownika. Mój klient chce, bym skonfigurował filtr do wyszukiwania użytkownika na podstawie tablicy napisów, w której wszystkie muszą być niewrażliwe na wielkość liter, zawarte w pełnej nazwie.Filtruj bazę danych Django dla pola zawierającego dowolną wartość w tablicy

Na przykład

Jeżeli użytkownicy full_name = "Keith, Thomson S."

i mam listę ['keith','s','thomson']

Chcę wykonać odpowiednik filtru

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

Problemem jest to lista ta może być o dynamicznym rozmiarze - więc nie wiem jak to zrobić.

Ktoś ma jakieś pomysły?

Odpowiedz

33

Dokonaj kolejnych połączeń do filter, tak:

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

Alternatywnie można & razem grono Q obiektów:

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

Bardziej tajemniczy sposób pisania tego, unikając wyraźnej pętlę :

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

Zastanawiam się, jak będzie wyglądać ostateczne wyrażenie sql po połączeniu wszystkich tych filtrów. – akonsu

+0

@akonsu Po prostu wypróbowałem to (no, coś podobnego) - zostaje ono przetłumaczone na ciąg 'AND's w klauzuli' where', tj. 'Full_name LIKE% keith% AND full_name LIKE% s% AND ... ' –

+2

@isbadawi, +1 - zauważ, że domyślnym operatorem dla wielu obiektów Q jest AND, więc możesz po prostu' * [Q1, Q2, Q3] 'bez użycia redukcji/operator.and_. –

2

somethi ng wzdłuż tych linii:


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

EDIT: to jest złe, PO chce nazwy, które zawierają wszystkie sznurki jednocześnie.

3

Nawet krótszy używając operator funkcje and_ lub or_ połączyć listę Q() warunkach

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

elementy, które spełniają wszystkie struny (and_)

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

przedmioty spełniające którykolwiek z ciągów (or_)

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

Funkcja Q() realizuje __or__() i __and__()Q() łączenia dwóch obiektów ze sobą, dzięki czemu można je wywołać za pomocą odpowiednich operator funkcji.

Powiązane problemy