I have a wizard that contain formA, formB, formC and formD. I want to skip FormB if FormA attribute开发者_如何学C name is not null. How could I do such a thing?
regards,
Create a view that will conditionally check which step of the process is currently being submitted then validate the form and also choose what form comes next.
forms.py
class BaseForm(forms.Form)
# All our forms will have a hidden field identifying them as either A, B or C
type = forms.HiddenField(...)
class formA(BaseForm)
# These are the rest of your attibutes (such as 'name' etc.)
a_1 = forms.TextField(...)
a_2 = forms.TextField(...)
class formB(BaseForm)
b_1 = forms.TextField(...)
b_2 = forms.TextField(...)
....
class formC(BaseForm)
c_1 = forms.TextField(...)
c_1 = forms.TextField(...)
views.py
This view could be called from the URL /form-wizard/ and will figure out which of the three forms it is receiving and which form it will provide for the next step. When all the data has been gather, some redirect or further logic can be performed.
def form_wizard(self, request):
next_form = None
curr_form = None
if request.method=='POST':
# Find out if we have received a form in our chain
type = request.POST.get("type", None)
if type == 'a':
# We are now processing Form A
curr_form = FormA(request.POST)
if curr_form.is_valid():
# Do a check on the attributes (i.e. name==None)
if curr_form.cleaned_data.get('a_1',None):
next_form = FormB()
# Now set the value of type to 'b' for the next form
next_form.fields['type'].initial = 'b'
else:
next_form = FormC()
next_form.fields['type'].initial = 'c'
elif type == 'b':
# Processing B
curr_form = FormB(request.POST)
if form.is_valid():
# Do something with this form
....
next_form = FormC()
next_form.fields['type'].initial = 'c'
elif type == 'c':
# Processing C
curr_form = FormC(request.POST)
if curr_form.is_valid():
# Last form in chain; either redirect or do something else
return HttpResponseRedirect(...)
else:
# First visit to the wizard, give them the first form
curr_form = FormA()
curr_form.fields['type'].initial = 'b'
return .... {'form':curr_form}
Finally, in your template:
template.html
This will render whichever form we have passed to the template (A,B or C)
...
<form action="/form-wizard/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
...
The only other problem you might face is how to keep data from the first form until you have succesfully completed the third form. This can be easily overcome by saving any valid form fields from the first form in the users session using Django's built in session handling:
https://docs.djangoproject.com/en/dev/topics/http/sessions/#examples
The django.contrib.formtools.wizard
app has been rewritten for Django 1.4. The new app has been backported as django-formwizard, which is available for Django 1.3.
If you are writing new formwizard views, I recommend that you use the django-formwizard app. This will make it easier to migrate to future versions of Django when the old formwizard code is deprecated.
There is a section in the Django docs for the development version of Django, describing how to skip specific steps of the formwizard.
If you're sticking with 1.3, FormWizard.process_step
is the hook you're looking for.
From the docs, you use this method to:
dynamically alter self.form_list, based on previously submitted forms.
A simple implementation would be:
def process_step(self, request, form, step):
if step == 1 && form.cleaned_data['name'] is not None:
self.form_list.pop(2)
精彩评论