开发者

django 1.3 wizard alter form_list to change next steps

开发者 https://www.devze.com 2023-04-05 12:40 出处:网络
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?

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)
0

精彩评论

暂无评论...
验证码 换一张
取 消