Как в 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
отфильтрованные по заполненным полям.
Для понимания **
здесь есть ответ