django-formtools icon indicating copy to clipboard operation
django-formtools copied to clipboard

FormWizard validates the last form twice

Open gchp opened this issue 11 years ago • 3 comments

This issue was originally submitted on Trac (#10810). See the previous link for the full conversation. Below is the original description:


FormWizard revalidates all the forms on the last step, after validating the last form. So the last one gets validated twice on the same request. In my app I have captcha on the last form and it does not work with revalidation (and should not I think). I've made changes to wizard.py, patch attached (see original Trac issue).

gchp avatar Oct 20 '14 18:10 gchp

An interesting comment from the Trac discussion:

Changing the re-validation and making the last step a special case isn't a good idea. Think about a case when someone want's to add a captcha in the first step.. this would break too.

What do you think about a list of "don't re-validate" forms/steps? This would give people a way to mark specific steps as "validating once is fine, skip this form when re-validating everything for the done method".

I think this is a good point. The case given here is that the validation is failing because this user's case had a captcha in the last form. However, should the captcha have been in any of the other forms, it would have failed too. I like the suggestion of allowing certain forms to skip the final validation better than just skipping the re-validation of the last form. Interested to hear what others think, though.

gchp avatar Mar 24 '15 00:03 gchp

We now have the same issue but we need to put the captcha on the first step.

As a workaround we will try to dynamically delete captcha field in get_form method if the form was already valid (there are data in the storage). If this works then generic solution can be made where you configure in which form which fields must be validated only once and then the wizard will automatically delete them when needed.

vstoykov avatar Aug 02 '16 14:08 vstoykov

here's a mixin. add it to the view

class PreventRevalidationMixin:
    NO_REVALIDATION_FIELD_NAMES = ['captcha']

    def process_step(self, form):
        for name in  self.NO_REVALIDATION_FIELD_NAMES:
           if name in form.fields:
               self.storage.extra_data[f'skip_validation{name}'] = True
        return super().process_step(form)

    def get_form(self, step=None, *args, **kwargs):
        form = super().get_form(step=step, *args, **kwargs)
        for name in self.NO_REVALIDATION_FIELD_NAMES:
           if name in form.fields and self.storage.extra_data.get(f'skip_validation{name}')
                del form.fields[name]
        return form

richtier avatar Nov 13 '19 11:11 richtier