Почему форма мастера 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")
Вернуться на верх