Restarting FormWizard from done method
-
13-07-2021 - |
Question
I'm trying use the FormWizard for to submit an order "charge" in wizard done
method. Extending the example in the documentation, performing the credit card "charge" in the done
means you can't go back and reprompt for credit card, because the wizard performs self.storage.reset()
after calling the done
method.
What is the right approach? The confirmation form clean()
step is called multiple times for revalidation, etc, & seems too removed from done()
where all validated forms are available.
Thanks for any pointers.
Kent
Solution 2
I guess the answer is "you can't get there from here". I opened a ticket #19189, but it's unclear this feature will be added.
OTHER TIPS
I could think of this:
- In
done()
method you will be charging the user. If its declined/failed, save each forms data in session/cookies. - Restart the wizard from specific step where payment info is taken. NamedUrlWizard might be helpful.
- Implement your
get_form_intial()
to return data from session/cookies for the step.
However, I think validation of this may fail as skipped steps do not have data. So you may have to do some more to get pass that.
Here is my solution: 1. extend WizardView, modify render_done method to catch exception in it: - detailed description
from django.contrib.formtools.wizard.views import SessionWizardView
class MySessionWizardView(SessionWizardView):
def __init__(self, **kwargs):
super(MySessionWizardView, self).__init__(**kwargs)
self.has_errors = False
class RevalidationError(Exception):
def __init__(self, step, form, **kwargs):
self.step = step
self.form = form
self.kwargs = kwargs
def __repr__(self):
return '%s(%s)' % (self.__class__, self.step)
__str__ = __repr__
def render_done(self, form, **kwargs):
final_form_list = []
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_form_list.append(form_obj)
try:
done_response = super(MySessionWizardView, self).render_done(form, **kwargs)
except self.RevalidationError as e:
return self.render_revalidation_failure(e.step, e.form, **e.kwargs)
self.storage.reset()
return done_response