-
-
Notifications
You must be signed in to change notification settings - Fork 143
Open
Labels
Description
This issue was originally submitted on Trac (#21667). I've added some snippets from the original ticket below, see the link above for the full conversation.
The WizardView does not currently support dynamic form classes without overriding the entire get_form method.
My mixin below demonstrates an easy way to make this convenient. I needed this functionality to support using modelform_factory at runtime to accommodate logic that varies depending on choices made previously in the wizard. A simple use case is to support dynamic "required" fields.
class WizardDynamicFormClassMixin(object):
def get_form_class(self, step):
return self.form_list[step]
def get_form(self, step=None, data=None, files=None):
"""
This method was copied from the base Django 1.6 wizard class in order to
support a callable `get_form_class` method which allows dynamic modelforms.
Constructs the form for a given `step`. If no `step` is defined, the
current step will be determined automatically.
The form will be initialized using the `data` argument to prefill the
new form. If needed, instance or queryset (for `ModelForm` or
`ModelFormSet`) will be added too.
"""
if step is None:
step = self.steps.current
# prepare the kwargs for the form instance.
kwargs = self.get_form_kwargs(step)
kwargs.update({
'data': data,
'files': files,
'prefix': self.get_form_prefix(step, self.form_list[step]),
'initial': self.get_form_initial(step),
})
if issubclass(self.form_list[step], forms.ModelForm):
# If the form is based on ModelForm, add instance if available
# and not previously set.
kwargs.setdefault('instance', self.get_form_instance(step))
elif issubclass(self.form_list[step], forms.models.BaseModelFormSet):
# If the form is based on ModelFormSet, add queryset if available
# and not previous set.
kwargs.setdefault('queryset', self.get_form_instance(step))
return self.get_form_class(step)(**kwargs)This is a simple demonstration of usage:
def get_form_class(self, step):
if step == STEP_FOO:
try:
choice_foo = self.get_cleaned_data_for_step(STEP_FOO)["choice_foo"]
except KeyError:
pass
else:
# get_wizard_form_class() would return a model form with fields
# that depend on the value of "choice"
return ModelFoo(choice=choice_foo).get_wizard_form_class()
return super(WizardFoo, self).get_form_class(step)