Как передать данные предыдущей формы конструктору 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 формы и переключил ее на определение 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

person BozoJoe    schedule 15.10.2010    source источник


Ответы (4)


FormWizard уже передает данные из каждой предыдущей формы в следующую форму. Если вы хотите получить эти данные для создания экземпляра класса (например, если форма требует специальных аргументов ключевого слова), один из способов сделать это — получить запрос, переопределив 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.user), которые понадобятся для всех форм, это может быть лучше получить данные оттуда.

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

person Jeremy Sandell    schedule 11.11.2010
comment
У меня возникла проблема с передачей данных с шага 1 на шаг 3, но ваше решение полезно и полезно. - person BozoJoe; 16.11.2010
comment
С какой проблемой вы столкнулись? Насколько я знаю, он должен позволить вам получить доступ ко всем данным из всех предыдущих форм, то есть на шаге 3 должны быть данные с шага 1 и шага 2. - person Jeremy Sandell; 16.11.2010
comment
моя проблема заключалась в том, что я пытался использовать начальный из мастера и переопределял форму init. Я перешел на использование get_form и мир становится для меня яснее :) - person BozoJoe; 18.11.2010

Я решил это, переопределив 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)
person Nick Gottlieb    schedule 22.10.2012

Переопределите метод 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 

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

формы.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()
person sunny    schedule 28.08.2013

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

next_form = self.form_list[1]

# let's 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 вы не можете объявить и назначить функцию за один раз и должны поместить ее в пространство имен (если вы не используете лямбда-выражения), ну да ладно.

person George Karpenkov    schedule 16.10.2010
comment
Я не уверен, что следую. Является ли этот код переопределением init подкласса FormWizard? Как это позволяет мне получать данные с шага 1 на шаг 2? - person BozoJoe; 19.10.2010
comment
нет, он переопределяет инициализацию следующей формы. Обратите внимание, что он говорит self.fields['availability'].choices = ..., теперь вместо ... вы можете поместить любые данные, которые хотите передать - person George Karpenkov; 19.10.2010
comment
У меня уже есть переопределенная next_form init, поэтому я до сих пор не вижу, как вы передаете данные из предыдущей формы мастера. - person BozoJoe; 19.10.2010
comment
О, этот код должен быть внутри метода process_step мастера - таким образом вы можете получить self.form_list[0].cleaned_data и основывать новый init на этом - person George Karpenkov; 20.10.2010