I’ve spent the last few days implementing a Django SessionWizardView and ran into what I thought would be a simple problem – how to access the data of a previous form in order to initialize a later form (i.e. use data submitted on step 1 to initialize the step 3 form). Google didn’t turn up much so I turned to the documentation for a solution.
At first glance it seemed simple enough – use get_cleaned_data_for_step or get_all_cleaned_data. The problem with these, I quickly discovered, is that they call get_form which in turn calls get_form_initial (which is where I’m trying to use the submitted form data in the first place). So that was a dead end.
Next up was using get_form_step_data. This method is called before get_form_initial and has access to both the form’s data and cleaned_data properties. The issue with this technique, however, is that it would require the data to be stored in some way for use in get_form_initial (either via a session variable or an instance variable). While this works, it still seemed like there had to be a better way. After all, the wizard is storing this data somewhere already.
So after a bit of digging in the source, the solution was obvious – self.storage.get_step_data(step).
This method allows you to pull the data from any step and will return either None or a MultiValueDict.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyWizardView(SessionWizardView): | |
# this runs for the step it's on as well as for the steps before | |
def get_form_initial(self, step): | |
# steps are named 'step1', 'step2', 'step3' | |
# get the data for step 1 | |
prev_data = self.storage.get_step_data('step1') | |
some_var = prev_data.get('step1-some_var','') | |
return self.initial_dict.get(step, {'some_var': some_var}) |
One final thing to note is that because get_form_initial is called for every previous step (with that previous step as the step argument), it’s probably likely you’ll need to know what step you’re actually on. You can do this by using self.storage.current_step.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyWizardView(SessionWizardView): | |
# this runs for the step it's on as well as for the step before | |
def get_form_initial(self, step): | |
# steps are named 'step1', 'step2', 'step3' | |
current_step = self.storage.current_step | |
# get the data for step 1 on step 3 | |
if current_step == 'step3': | |
prev_data = self.storage.get_step_data('step1') | |
some_var = prev_data.get('step1-some_var','') | |
return self.initial_dict.get(step, {'some_var': some_var}) | |
return self.initial_dict.get(step, {}) |
If anyone knows of a better way to do this, I’d love to know.
Interesting approach, I’ve bumped into this problem as well, the only downside of your solution, is you don’t get the “cleaned” value, so in case of date, datetime, you need to parse it manually, but I guess that’s small price to pay comparing to overkill with regenerating prev forms, especially if there’s sql involved in form init..
Anyway thanks for the tip. Hope to see more 😉
Actually you do get the cleaned data. If you look at the method definition for set_step_data, you’ll see that the cleaned_data is what is being saved to the storage:
hmm I guess it’s “to_python” that is not processed then..
Reblogged this on nerd diaries.
Ran into the same issue. A simple way to get all the step data in the context is to append it using get_context_data and get_all_cleaned_data.
https://docs.djangoproject.com/en/1.7/ref/contrib/formtools/form-wizard/#django.contrib.formtools.wizard.views.WizardView.get_context_data
https://docs.djangoproject.com/en/1.7/ref/contrib/formtools/form-wizard/#django.contrib.formtools.wizard.views.WizardView.get_all_cleaned_data
def get_context_data(self, form, **kwargs):
context = super(MyWizard, self).get_context_data(form=form, **kwargs)
context[‘wizard_data’] = self.get_all_cleaned_data()
return context