Джанго поиск объектов по нескольким ключам

Я пытаюсь подготовить форму поиска, в которой пользователь может ввести 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_ вместо.

Другие вопросы по тегам