python / expert
Snippet
Django Form Wizard with Multi-Step Validation and Conditional Branching
Django FormWizard with SessionWizardView manages multi-step form submission with server-side state persistence. Conditional branching is achieved by overriding get_form_instance and get_template_names based on previous step data. The corporate step is conditionally shown based on account_type selection, demonstrating how wizard steps can dynamically adapt without JavaScript dependencies.
snippet.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from django.shortcuts import renderfrom formtools.wizard.views import SessionWizardfrom django import formsfrom django.core.exceptions import ValidationErrorclass PersonalForm(forms.Form):full_name = forms.CharField(max_length=100)email = forms.EmailField()account_type = forms.ChoiceField(choices=[('individual', 'Individual'), ('corporate', 'Corporate')])class CorporateForm(forms.Form):company_name = forms.CharField(max_length=200)tax_id = forms.CharField(max_length=50)employee_count = forms.IntegerField(min_value=1)class PreferencesForm(forms.Form):newsletter = forms.BooleanField(required=False)notifications = forms.BooleanField(required=False)FORMS = [('personal', PersonalForm), ('corporate', CorporateForm), ('preferences', PreferencesForm)]TEMPLATES = {'personal': 'wizard/personal.html', 'corporate': 'wizard/corporate.html', 'preferences': 'wizard/prefs.html'}class MultiStepWizard(SessionWizardView):def get_template_names(self):return [TEMPLATES[self.steps.current]]def get_form_instance(self, step):if step == 'corporate':return self.instance_dict.get('corporate') or {}return {}def get_form_initial(self, step):initial = super().get_form_initial(step)if step == 'preferences':initial['newsletter'] = Truereturn initialdef done(self, form_list, **kwargs):data = {k: v for form in form_list for k, v in form.cleaned_data.items()}return render(self.request, 'wizard/done.html', {'data': data})
django
Breakdown
1
class MultiStepWizard(SessionWizardView):
SessionWizardView persists form data across requests server-side
2
def get_template_names(self): return [TEMPLATES[self.steps.current]]
Returns template based on current wizard step for dynamic rendering
3
def get_form_initial(self, step):
Pre-populates form fields based on step context
4
if step == 'preferences': initial['newsletter'] = True
Conditional initialization of newsletter default
5
data = {k: v for form in form_list for k, v in form.cleaned_data.items()}
Merges all form cleaned_data into single dictionary on completion