SessionWizardView state only saved on final form, done() not executed
Asked Answered
R

2

7

I have several forms I have added to a wizard, but form state is only maintained for the final step, and done() is not executed.

I have created the following, heavily based off the examples on django's documentation, to try get to the bottom of this. It seems the final step is the only one that saves the state when moving amongst the steps.

class OneForm( Form ):
    field_one = forms.CharField(label='1', max_length=100)
    field_two = forms.CharField(label='2', max_length=100)
    field_three = forms.CharField(label='3', max_length=100)
class TwoForm( Form ):
    field_one = forms.CharField(label='4', max_length=100)
    field_two = forms.CharField(label='5', max_length=100)
    field_three = forms.CharField(label='6', max_length=100)

TEST_WIZARD_FORMS = [
    ("one", OneForm),
    ("two", TwoForm),
]
TEST_TEMPLATES = {
    'one': 'tour/one.html',
    'two': 'tour/two.html',
}
class TestWizardView( SessionWizardView ):
    form_list = TEST_WIZARD_FORMS
    def done(self, form_list, **kwargs):
        print('done executed')
        return reverse('home')
    def get_template_names(self):
        return [TEST_TEMPLATES[self.steps.current]]

and this for templates (both one.html and two.html are identical)

<html>
<body>
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post">{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
    {{ wizard.form.management_form }}
    {{ wizard.form.non_field_errors }}
    {{ wizard.form.errors }}
    {% for form in wizard.form.forms %}
        {{ form }}
    {% endfor %}
{% else %}
    {{ wizard.form }}
{% endif %}
</table>
{% if wizard.steps.prev %}
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">"first step"</button>
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">"prev step"</button>
{% endif %}
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.next }}">"next step"</button>
<input type="submit" value="submit"/>
</form>
</body>
</html>

If I enter data on step 1, proceed to step 2 and enter data, then return to step 1, the first step has no data saved and no form errors displayed. When I hit next to return to step 2, step 2's data is still present. Intentionally putting invalid data on step 1 has shown me that it does not validate the form either, as the wizard continues to step 2 without displaying errors.

When I submit the form, done() does not execute. This makes sense if only the last step is actually successful, but seeing no errors on step 1 has me baffled.

Why is form data not maintained except on the final form? Why is the final step the only one that actually validates form data? Why is done not executed?

Update: It appears the form validation is happening afterall, and I do see it succeeding via printing relevant information in the post function, but done() still does not seem to get executed.

Thank you.

Rollmop answered 10/11, 2015 at 4:43 Comment(0)
R
4

Step 1 in the documentation found here is the answer. It states the following.

The user visits the first page of the wizard, fills in the form and submits it.

The key here is the "submit." No form validation or state is saved unless the form is submitted. Using the wizard_goto_step for next/previous/jump does not submit the form, does not validate the form, and does not save the form in the session/cookie (depending which you choose).

It is obvious now, but I still think this is misleading to potential end users of the form wizard. It is easy enough for me to replace the wizard_goto_step with an actual submit when going to the next step, but when users enter some data in a form, and subsequently choose to revisit another step, all of their data on that step is lost.

It feels like form data should be saved even when incomplete. My intention is to save this data manually using the storage.set_step_data() function, as all form steps are re-validated at the final processing anyway. Even if a user fills out incorrect data on a step they will still be redirected to the step with missing data at the end. This feels like better behavior than blindly wiping the user's data on a step when they visit a previous step.

Rollmop answered 25/1, 2016 at 1:39 Comment(2)
Hi Wilbbe! I am facing the same issue of the done() not getting executed and the ui jumping to 1st step after the last step without any errors. Being a novice at django Could you please direct me with an example if possible.This is my SO post #56635882Afeard
@subbu, it has been a while since I did much with the form wizard stuff, but what I do remember should be included in what I wrote below. Bottom line......the form wizard was not as naturally intuitive as it felt it should be. Reading carefully through how it works “solved” things for me. I assume you may be in a similar boat as I was, where what you assume it is supposed to do is not accurate. I haven’t looked recently, but I’d bet there is a better alternative 3rd party form system out there that is more meant to maintain state and jump between different steps of the form.Rollmop
I
0

It is certainly a bug. You have to remove the following lines of code from

\formtools\wizard\views.py

        # walk through the form list and try to validate the data again.
#         for form_key in self.get_form_list():
#             form_obj = self.get_form(step=form_key,
#                 data=self.storage.get_step_data(form_key),
#                 files=self.storage.get_step_files(form_key))
#             if not form_obj.is_valid():
#                 return self.render_revalidation_failure(form_key,
#                                                         form_obj,
#                                                         **kwargs)
#             final_forms[form_key] = form_obj

Actually I don't understand the reason of this code. Every form was validated after it was submitted. I see no reason to validate them again?

This validation fails for some unknown reason, and that is why the done routine later on is never called.

Inform answered 12/9, 2016 at 22:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.