Как передать данные предыдущей формы в конструктор DynamicForm в FormWizard

У меня есть FormWizard, где мне нужны данные из первой формы, чтобы передать конструктору второй формы, чтобы я мог создать динамическую форму.

Я могу получить первые данные формы через process_step из FormWizard.

Я создаю поля второй формы с вызовом базы данных из списка полей.

class ConditionWizardDynamicQuestions(forms.Form):

    def __init__(self, DynamicQuestions=None, *args, **kwargs):
       super(ConditionWizardDynamicQuestions, self).__init__(*args, **kwargs)
       questions = Question.objects.filter(MYDATA = DATA_FROM_1STFORM)
       for q in questions:
            dynField = FieldFactory(q)
            self.fields[q.label] = dynField

Как я могу передать DATA_FROM_1STFORM?


мой итоговый код: Я отказался от init формы и переключил его на def CreateQuestions. Затем использовалось переопределение мастера get_form для изменения формы после создания.

class ConditionWizard(SessionFormWizard):
    def get_form(self, request, storage, step=None, data=None, files=None):
        form = super(ConditionWizard, self).get_form(request, storage, step, data, files)
        stepIndex = self.get_step_index(request, storage, step)
        if stepIndex == 1:
            form.CreateQuestions(request.session["WizardConditionId"])
        if stepIndex == 3:
            form.fields['hiddenConditionId'].initial = request.session["WizardConditionId"]
            form.fields['medicationName'].queryset = Medication.objects.filter(condition = request.session["WizardConditionId"])
        return form

Ответ 1

FormWizard уже передает данные из каждой предыдущей формы в следующую форму. Если вы хотите получить эти данные, чтобы создать экземпляр класса (например, если форма имеет специальные аргументы ключевого слова, которые она требует), один из способов сделать это - захватить querydict, переопределив get_form в классе макета формы. Например:

class SomeFormWizard(FormWizard):
    def get_form(self, step, data=None):
        if step == 1 and data: # change this to whatever step requires
                               # the extra data
            extra_data = data.get('key_from_querydict')
            if extra_data:
                return self.form_list[step](data,
                                            keyword_argument=extra_data,
                                            prefix=self.prefix_for_step(step),                                                                                                                                            
                                            initial=self.initial.get(step, None))
        # Fallback for the other forms.
        return self.form_list[step](data,
                                    prefix=self.prefix_for_step(step),                                                                                                                                            
                                    initial=self.initial.get(step, None))

Обратите внимание, что вы также можете переопределить parse_params(self, request, *args, **kwargs) в FormWizard для доступа к данным url/request, как и в представлении, поэтому, если у вас есть данные запроса (request.user, например), которые понадобятся для всех форм, возможно, лучше получить данные оттуда.

Надеюсь, что это поможет.

Ответ 2

Я решил это, переопределив get_form_kwargs для WizardView. Обычно он возвращает пустой словарь, который заполняет get_form, поэтому, переопределяя его, чтобы вернуть словарь с необходимыми предварительными данными, вы можете передать kwargs в свою форму init.

def get_form_kwargs(self, step=None):
    kwargs = {}
    if step == '1':
        your_data = self.get_cleaned_data_for_step('0')['your_data']
        kwargs.update({'your_data': your_data,})
    return kwargs

Затем, в вашем методе init, вы можете просто выпустить kwarg перед вызовом super:

self.your_data = kwargs.pop('client', None)

Ответ 3

Переопределить метод get_form_kwargs мастера формы в представлениях

view.py

class FormWizard(SessionWizardView):
    def get_form_kwargs(self, step=None):
        kwargs = {}
        if step == '1':
            step0_form_field = self.get_cleaned_data_for_step('0')['previous_form_field_data']
            kwargs.update({'step0_form_field': step0_form_field})
        return kwargs 

Отмените инициализацию своей формы, выбирая данные, полученные из предыдущего поля, для создания динамического поля.

forms.py

class MyForm(forms.Form):
    #some fields

class MyForm1(forms.Form):
    def __init__(self, *args, **kwargs):
        extra = kwargs.pop('step0_form_field')
        super(MyForm1, self).__init__(*args, **kwargs)

        for i in range(extra):
            self.fields['name_%s' % i] = forms.CharField()

Ответ 4

Недавно я работал с мастером формы django, и я решал аналогичную проблему. Я не думаю, что вы можете передать данные в init, однако то, что вы можете сделать, переопределяет конструктор init:

next_form = self.form_list[1]

# let change the __init__
# function which will set the choices :P
def __init__(self, *args, **kw):
    super(next_form, self).__init__(*args, **kw)
    self.fields['availability'].choices = ...
next_form.__init__ = __init__

Это довольно раздражает то, что в python вы не можете объявлять и назначать функцию за один раз и должны помещать ее в пространство имен (если вы не используете lambdas), но хорошо.