Почему форма мастера django не отправляется, когда одна форма передается через функцию get_form?
Я создаю приложение, содержащее 3 вопроса с множественным выбором. Варианты второго множественного выбора зависят от ответа на первый вопрос. Для этого я добавил аргумент "choices" во вторую форму и вызвал этот аргумент в функции get_form мастера.
Хотя внешне все работает нормально, проблема возникает при попытке отправить форму на последнем шаге. Функция done() никогда не вызывается, как и функция clean() в файле forms.py. Страница просто обновляется без появления каких-либо ошибок, а существующие выбранные опции стираются.
В результате тестирования я пришел к выводу, что удаление пользовательского init из forms.py и get_form из views.py решает проблему - но, очевидно, это не достигает цели. Я уже очень долго пытаюсь решить эту проблему, но никак не могу, любая помощь будет очень признательна!
views.py
class FormWizardView(SessionWizardView):
form_list = [FormReflectionOne, FormReflectionTwo]
template_name = 'reflection/form.html'
def done(self, form_list, **kwargs):
form_data = [form.cleaned_data for form in form_list]
# Save form_data to Reflection Model
return redirect('dashboard')
def get_form(self, step=None, data=None, files=None):
if step is None:
step = self.steps.current
if step == '1':
firststep_data = self.get_cleaned_data_for_step('0')
choices_list = AdjectiveChoice.objects.filter(feeling=firststep_data['feeling'])
choices = [(x.order, x.adjective) for x in choices_list]
form = FormReflectionTwo(choices)
else:
return super(FormWizardView, self).get_form(step, data, files)
return form
forms.py
class FormReflectionTwo(forms.Form):
def __init__(self, choices, *args, **kwargs):
super(FormReflectionTwo, self).__init__(*args, **kwargs)
self.fields['adjective'].choices = choices
def clean(self):
cleaned_data = super(FormReflectionTwo, self).clean()
adjective = cleaned_data.get('adjective')
reason = cleaned_data.get('reason')
if adjective and reason:
if len(adjective) > 3:
raise ValidationError({'adjective': "Pick 1 to 3 adjectives"})
if len(reason) > 3:
raise ValidationError({'reason': "Pick 1 to 3 reasons"})
return cleaned_data
adjective = forms.MultipleChoiceField(choices=ADJECTIVE_CHOICES, widget=forms.CheckboxSelectMultiple, required=True)
reason = forms.MultipleChoiceField(choices=REASON_CHOICES, widget=forms.CheckboxSelectMultiple, required=True)
class Meta:
model = ReflectionEntry
fields = ['adjective', 'reason']
Небольшие другие заметки: Переменная ADJECTIVE_CHOICES - это просто полный список всех вариантов прилагательных, я знаю, что она не нужна, но она здесь в качестве запасного варианта. Модель AdjectiveChoice хранит все возможные варианты, а также то, для какого ответа на "вопрос 1" они предназначены.
Еще раз спасибо!
Если вы посмотрите на код метода get_form, там есть много настроек, которые выполняются для подготовки формы к работе с мастером форм. В вашем случае, я подозреваю, что префиксы формы, установленные методом get_form_prefix, нарушают логику мастера форм.
(Метод 1) Чтобы достичь желаемого, вы можете продолжить ту же мысль об использовании get_form, и установить атрибут choices поля после получения формы, как предложено в документации :
def get_form(self, step=None, data=None, files=None):
form = super().get_form(step, data, files)
# determine the step if not given
if step is None:
step = self.steps.current
if step == '1':
firststep_data = self.get_cleaned_data_for_step('0')
choices_list = AdjectiveChoice.objects.filter(feeling=firststep_data['feeling'])
choices = [(x.order, x.adjective) for x in choices_list]
form.fields['adjective'].choices = choices
return form
(Метод 2) Чтобы добиться желаемого, нужно переопределить метод get_form_kwargs для передачи коисов в init вашей формы:
def get_form_kwargs(self, step=None):
"""
Returns the keyword arguments for instantiating the form
(or formset) on the given step.
"""
if step == "1":
firststep_data = self.get_cleaned_data_for_step('0')
choices_list = AdjectiveChoice.objects.filter(feeling=firststep_data['feeling'])
choices = [(x.order, x.adjective) for x in choices_list]
return {"choices": choices}
return {}
и вы найдете их в вашей форме init в kwargs:
forms.py
class FormReflectionTwo(forms.Form):
def __init__(self, *args, **kwargs):
super(FormReflectionTwo, self).__init__(*args, **kwargs)
self.fields['adjective'].choices = kwargs.get("choices")