Well, I found a solution that does not use ajax at all and seems to me quite enjoyable:
Create as many forms as necessary, and subclass them to each other. Put the integer hidden field in the first:
class Form1(forms.Form): _nextstep = forms.IntegerField(initial = 0, widget = forms.HiddenInput()) foo11 = forms.IntegerField(label = u'First field of the first form') foo12 = forms.IntegerField(label = u'Second field of the first form') class Form2(Form1): foo21 = forms.CharField(label = u'First field of the second form') class Form3(Form2): foo31 = forms.ChoiceField([], label=u'A choice field which choices will be completed\ depending on the previous forms') foo32 = forms.IntegerField(label = u'A last one')
Ok, now for the forms now look:
def myview(request): errors = [] # define the forms used : steps = [Form1,Form2,Form3] if request.method != 'POST': # The first call will use the first form : form = steps[0]() else: step = 0 if request.POST.has_key('_nextstep'): step = int(request.POST['_nextstep']) # Fetch the form class corresponding to this step # and instantiate the form klass = steps[step] form = klass(request.POST) if form.is_valid(): # If the form is valid, increment the step # and use the new class to create the form # that will be displayed data = form.cleaned_data data['_nextstep'] = min(step + 1, len(steps) - 1) klass = steps[data['_nextstep']] form = klass(data) else: errors.append(form.errors) return render_to_response( 'template.html', {'form':form,'errors':errors}, context_instance = RequestContext(request))
The only problem that I encountered is that if you use {template}} in your template, it causes form.errors and therefore automatically confirms the new form (for example, Form2) with the data of the previous one (Form1). So what I do is iterate over the elements in the form and use only {{item.id}}, {{item.label}} and {{item}}. Since I already selected the errors of the previous form in the view and passed this to the template, I add a div to display them on top of the page.
source share