Предварительное заполнение поля выбора Django ChoiceField внутри набора форм
У меня есть набор форм с полем Runner
, которое должно иметь некоторое значение из модели Runner
.
Я использую виджет select2 для заполнения этого значения: когда пользователь что-то набирает, я использую Ajax для запроса соответствующих строк из базы данных.
Теперь я хочу сохранить значения, которые это поле сохраняет, когда я отправляю свой набор форм, на случай, если произойдет какая-то ошибка и мне придется снова показать эту форму.
Если я определяю это поле как ChoiceField
с choices=[]
, открываю форму и выбираю некоторое runner
(например, с id
=123), то после отправки POST-запроса и попытки инициализировать мой набор форм с FormsetResult(data=request.POST)
, я получаю ошибку, что предоставленное значение не представлено в списке choices
, что является истиной.
Я попытался добавить это значение к choices
в конструкторе формы:
def __init__(self, *args, **kwargs):
runner_id = None
if self.fields['runner'].initial:
runner_id = kwargs['initial'].get('runner')
runner = models.Runner.objects.filter(pk=runner_id).first()
if runner:
self.fields['runner'].choices = [('', ''), (runner_id, runner.get_name())]
, но это все равно не работает после отправки формы: initial
значения теперь пустые, а в случае наборов форм, POST
словарь имеет уродливые имена полей, такие как form-0-runner
, что затрудняет извлечение нужного мне значения.
Другой вариант - написать какой-нибудь хак в шаблоне, который будет загружать из БД нужное мне значение:
<select name="form-{{ forloop.counter0 }}-runner" id="id_form-{{ forloop.counter0 }}-runner">
{% if form.instance.runner %}
<option value="{{ form.instance.runner.id }}" selected>{{ form.instance.runner.get_name }}</option>
{% endif %}
</select>
, но это тоже не красиво.
Может быть, вы видите лучший способ достичь этого? Возможно, приложение Django-Select2 поможет мне в этом?
Вам необходимо переопределить метод __init__
в вашей форме
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
#if form input is empty
self.fields['runner'].queryset = Runner.objects.none()
# if user typed something
if 'runner' in self.data:
self.fields['runner'].queryset = Runner.objects.all()
# if object exists it will set the value of field to previously saved one
elif self.instance.pk:
self.fields['runner'].queryset = Runner.objects.all().filter(pk=self.instance.runner.pk)