Как передать данные предыдущей формы в конструктор 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), но хорошо.