I'm trying to pass data from my view to my form class using WizardView.
Without WizardView, I do this using get_forms_kwargs() like the below:
def get_form_kwargs(self):
kwargs = super(MenuAddWizard, self).get_form_kwargs()
kwargs.update({'month': self.kwargs['month']})
return kwargs
And in my form class I use:
def __init__(self, *args, **kwargs):
self.month = kwargs.pop('month', None)
All good - I'm able to use 'month' for validation in e.g. clean().
When I'm using WizardView though, I'm specifying the step in get_forms_kwargs() as follows, per the docs:
def get_form_kwargs(self, step=0):
kwargs = super(MenuAddWizard, self).get_form_kwargs()
kwargs.update({'month': self.kwargs['month']})
return kwargs
My get_form() doesn't like this:
File "python312\Lib\site-packages\formtools\wizard\views.py", line 311, in post
return self.render_next_step(form)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "python312\Lib\site-packages\formtools\wizard\views.py", line 322, in render_next_step
new_form = self.get_form(
^^^^^^^^^^^^^^
File "myproject\views.py", line 1614, in get_form
form = super().get_form(step, data, files)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "python312\Lib\site-packages\formtools\wizard\views.py", line 432, in get_form
return form_class(**kwargs)
^^^^^^^^^^^^^^^^^^^^
TypeError: BaseFormSet.__init__() got an unexpected keyword argument 'month'
Any idea how to properly pass kwargs (or any other way) to a form with Django Form Wizard?
For reference, the full view is below (without get_forms_kwargs()):
class MenuAddWizard(LoginRequiredMixin, SessionWizardView):
# Either provide form_list as part of .as_view() in urls, or here.
form_list = [MenuInputForm, DayMenuFormSet]
template_name = "menu_add.html"
def get_context_data(self, form, **kwargs):
context = super(MenuAddWizard, self).get_context_data(form=form, **kwargs)
month = self.kwargs['month']
context['month'] = month
return context
def get_form_kwargs(self):
kwargs = super(MenuAddWizard, self).get_form_kwargs()
kwargs.update({'month': self.kwargs['month']})
return kwargs
def get_form(self, step=None, data=None, files=None):
form = super().get_form(step, data, files)
if step is None:
step = self.steps.current
if step == '1':
step_0_cleaned_data = self.get_cleaned_data_for_step('0')
# Using step 0 data, I generate the list to be used for initial; removing logic for brevity and using two example items as test
DayMenuFormSet = formset_factory(form=DayMenuForm, extra=0)
formset = DayMenuFormSet(initial=[{'menu': 'Some example text'}, {'menu': 'This is another test...'}],
data=data)
form = formset
return form
My forms are all inheriting from the standard forms.Form.
You seem to use a FormSet, probably made out of your form. Then you need to pass the values through the form_kwargs=… parameter [Django-doc], so:
def get_form_kwargs(self, *args, **kwargs):
result = super().get_form_kwargs(*args, **kwargs)
result.update(form_kwargs={'month': self.kwargs['month']})
return result
or perhaps simpler:
def get_form_kwargs(self, *args, **kwargs):
return {
**super().get_form_kwargs(*args, **kwargs),
'form_kwargs': {'month': self.kwargs['month']},
}
EDIT: the problem seems to be that you use a FormSet for a certain step, and a (simple) Form for other steps.
You should pass the value as month if it is for a (simple) form, and through form_kwargs for a FormSet, so:
class MenuAddWizard(LoginRequiredMixin, SessionWizardView):
# …
def get_form_kwargs(self, step=None, *args, **kwargs):
result = super().get_form_kwargs(step=step, *args, **kwargs)
if str(step) == '0':
result.update(month=self.kwargs['month'])
else:
# if used for a forms in a FormSet, probably not
# result.update(form_kwargs={'month': self.kwargs['month']})
pass
return result
# …
Note: Since PEP-3135 [pep], you don't need to call
super(…)with parameters if the first parameter is the class in which you define the method, and the second is the first parameter (usuallyself) of the function.