Как в Django проигнорировать objects.filter(request.POST['brand']) и достать все объекты?

Делаю сайт по покупке автомобилей, на котором есть форма (фильтр) которая отправляет POST.

В модели Ads находятся объекты с такими полями: brand_id, model_id, generation_id.

Проблема: Если на сайте в фильтре позиция "BRAND" не будет выбрана, то в request.POST['brand'] вернётся: '' (пустая строка, потому что <option value="">, поэтому вывод можно изменить). Тогда будет эта ошибка: ValueError: Field 'id' expected a number but got ''. Но суть не в ошибке, мне нужно чтобы если ничего не выбрано, то чтобы Django вернул все объекты, то есть проигнорировал фильтр brand_id.

Вот код из views.py:

context = {
           'Body': Brand.objects.all(),
           'EngineType': EngineType.objects.all(),
           'BoostType': BoostType.objects.all(),
           }

context['Ads'] = Ads.objects.filter(brand_id=request.POST['brand'],
                                    model_id=request.POST['model'],
                                    generation_id=request.POST['generation'],
                                    )

return render(request, 'ADS/main.html', context)

Прошу помочь. Если есть идеи, как сделать это совсем по-другому (лучше), то с удовольствием выслушаю.

Если в вашей форме это поле является необязательным, и вы хотите возвращать все объекты если brand пустое, то:

# если ничего не выбрали, то филтруем без request.POST['brand']
if request.POST['brand'] == '': 
    ads = Ads.objects.filter(
        model_id=request.POST['model'],
        generation_id=request.POST['generation'],
    )
else:
    ads = Ads.objects.filter(
        brand_id=request.POST['brand'],
        model_id=request.POST['model'],
        generation_id=request.POST['generation'],
    )


context = {
    'Body': Brand.objects.all(),
    'EngineType': EngineType.objects.all(),
    'BoostType': BoostType.objects.all(),
    # мне кажется, глазам легче по коду искать конкретную переменную
    # чем непонятно в каком месте добавление нового ключ-значения
    'Ads': ads
}

return render(request, 'ADS/main.html', context)

Но на всякий случай напишу, что если поле формы нужно сделать обязательным, то к <select> необходимо установить атрибут required:

<!-- например так -->
<select name="brand" required>

UPD:

Сейчас стало понятно, что вам нужен Q класс. Почитать подробно как он работает, можно в оф документации.

Какая логика:

Тк вы пишите, что полей много, больше 10, то необходимо создать цикл, что бы проверять, что поле заполнено. Если этого не сделать то будут искаться пустые поля. Пример:

# создаем словарь и в него передаем все ваши поля
filter_parametr = {
    'brand': request.POST['brand'],
    'model': request.POST['model'],
    'generation': request.POST['generation'],
    # остальные ваши поля
}

Далее создаем цикл и фильтр, и проверяем поля, если поле заполнено, то добавляем в фильтр:

filters = Q()

for key, value in filter_parametr.items():
    if value:
        # распаковываем в аргументы
        filters &= Q(**{f"{key}_id": value})

И далее вставляете фильтр в сам запрос:

ads = Ads.objects.filter(filters)

В результате будут возвращаться объекты Ads отфильтрованные по заполненным полям.

Для понимания ** здесь есть ответ

Вернуться на верх