Reputation:
I'm trying to create a simple Django multi-page form using FormWizard. What the form should do is the following:
In step 2, I'm having trouble figuring out how to display the information that the visitor entered in step 1. I'm posting the code for the forms and the two templates used for step 1 and 2 below:
forms.py
from django import forms
from django.shortcuts import render_to_response
from django.contrib.formtools.wizard import FormWizard
class ContactWizard(FormWizard):
def done(self, request, form_list):
return render_to_response('done.html', {
'form_data': [form.cleaned_data for form in form_list],
})
def get_template(self, step):
return 'buydomain/templates/reg%s.html' % step
class Form1(forms.Form):
firstName = forms.CharField()
lastName = forms.CharField()
class Form2(forms.Form):
message = forms.CharField(widget=forms.Textarea)
template for step 1:
{% block content %}
<p>Step {{ step }} of {{ step_count }}</p>
<form action="." method="post">
<table>
{{ form }}
</table>
<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
{{ previous_fields|safe }}
<input type="submit">
</form>
{% endblock %}
template for step 2:
{% block content %}
<p>Step {{ step }} of {{ step_count }}</p>
{% comment %}
Show values entered into Form1 here !
{% endcomment %}
<form action="." method="post">
<table>
{{ form }}
</table>
<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
{{ previous_fields|safe }}
<input type="submit">
</form>
{% endblock %}
I apologize if I'm somewhat unclear about what I want to achieve, and I'm hopefully waiting for someone to supply a solution. Thanks in advance.
Upvotes: 7
Views: 5334
Reputation: 129
Just some general advice first - if you don't understand how to use something in Django, pull out that text editor and take a look at the code. It's not always the fastest way to get an answer, but I believe it pays dividends in the long run.
Try adding some extra_context to the second step by overriding process_step in your FormWizard subclass. Here are the comments from within FormWizard (django 1.1):
def process_step(self, request, form, step):
"""
Hook for modifying the FormWizard's internal state, given a fully
validated Form object. The Form is guaranteed to have clean, valid
data.
This method should *not* modify any of that data. Rather, it might want
to set self.extra_context or dynamically alter self.form_list, based on
previously submitted forms.
Note that this method is called every time a page is rendered for *all*
submitted steps.
"""
pass
so in your own ContactWizard class, something like (NB: I did not run this):
class ContactWizard(FormWizard):
def process_step(self,request,form,step):
if step == 1:
self.extra_context = {'whatever': form.whatever_you_want_from_the_form}
return
else:
return
Upvotes: 6
Reputation: 231
Toby Panzer's answer doesn't allow the form class to access the extra context data -- only the template the form is displayed on has access. That said, that sounds like it's probably what you need. However, if you need the form to have access, I solved that by overriding get_form_kwargs. It normally just returns an empty dictionary that get_form populates, so by overriding it to return a dictionary with the data you need prepopulated, you can pass kwargs to your form init.
def get_form_kwargs(self, step=None):
kwargs = {}
if step == '1':
your_data = self.get_cleaned_data_for_step('0')['your_data']
kwargs.update({'your_data': your_data,})
return kwargs
Then, in your form init method you can just pop the kwarg off before calling super:
self.your_data = kwargs.pop('client', None)
Upvotes: 4
Reputation: 1015
I don't know if it's useful to still post this solution. Nevertheless. Needing stuff between the different forms (steps) used by the Wizard, are easily accessible when you give the wizard an extra attrib in the form of a dict. Like so:
class WizardRegistration(FormWizard):
def __init__(self, *args, **kwargs):
super(WizardRegistration, self).__init__(*args, **kwargs)
setattr(self, 'chosen', {})
Between the steps you can then easily take form or Model stuff and store it until you reach the done() method. Store a form value
self.chosen['something_to_store'] = form.cleaned_data.get('a_form_value')
Or even get/change/save a model:
object = Model.objects.get('some_query')
if self.chosen['object']:
self.chosen['object'].string = 'Something stringy'
self.chosen['object'].save()
Upvotes: 3