Джанго поиск объектов по нескольким ключам
Я пытаюсь подготовить форму поиска, в которой пользователь может ввести 1, 2 или все (в нашем случае 3) поисковые фильтры.
Допустим, что фильтрами поиска являются: фамилия, телефон и адрес. Я пытаюсь отфильтровать набор запросов по:
if filterForm.is_valid():
last_name = filterForm.cleaned_data.get('last_name')
phone= filterForm.cleaned_data.get('phone')
address = filterForm.cleaned_data.get('address')
if last_name is None and phone is None and address is None:
pass
#we dont do search id db
else:
clients = Client.objects.filter(Q(last_name__contains=last_name) | Q(phone=phone) | Q(address__contains=address))
Каждый ключ поиска может быть пустым.
К сожалению, он возвращает больше результатов, чем ожидалось. Когда я набираю поисковый фильтр "Пример" в качестве поля фамилии, он возвращает все поля с этой фамилией + много других строк.
Любая идея, как исправить эту проблему поиска?
1 ответ
Я считаю, что ваш поиск возвращает больше результатов, чем ожидалось, если любой из ключей поиска пуст, поскольку пустой ключ будет соответствовать любой строке со значением.
Фильтрация только по ключам, содержащим значение, должна работать лучше.
Вот один пример того, как это можно сделать:
if filterForm.is_valid():
last_name = filterForm.cleaned_data.get('last_name')
phone= filterForm.cleaned_data.get('phone')
address = filterForm.cleaned_data.get('address')
import operator
predicates = []
if last_name:
predicates.append(Q(last_name__contains=last_name))
if phone:
predicates.append(Q(phone=phone))
if address:
predicates.append(Q(address__contains=address))
if len(predicates) == 0:
# Nothing to search for
pass
else:
clients = Client.objects.filter(reduce(operator.or_, predicates))
Приведенный выше код будет динамически добавлять фильтры, которые должны быть добавлены в запрос. Использование oprator.or_
объединит заявления с OR
(= хотя бы одно утверждение должно быть удовлетворено). Если вместо этого вы хотите, чтобы все утверждения были удовлетворены, вы можете использовать operator.and_
вместо.