Move From django-formtools¶
Problem¶
You maintain a multi-step flow built on the django-formtools WizardView and want the equivalent in next.dj.
Solution¶
Port the flow to a next.forms.FormWizard.
The step forms move unchanged, the wizard hooks keep the formtools vocabulary, and the URL wiring disappears.
Declare the ordered steps under Meta.steps, place the wizard on a route with a [step] segment, and move the finalising code into done.
Build a Multi-Step Wizard walks through a complete wizard from scratch.
Method Map¶
The wizard API deliberately reuses the formtools names where the semantics match.
formtools |
|
|---|---|
|
|
|
A |
|
|
|
|
|
|
|
|
|
The |
|
The |
|
No equivalent, see Files in Steps. |
|
Auto-registration on subclassing, no URLconf entry. |
What Changes in Substance¶
No URL Plumbing¶
A WizardView is a class-based view mounted with as_view in urlpatterns.
A FormWizard registers itself the moment Python runs the class statement and lives on a routed page, where the [step] directory captures the current step.
See Form Wizards for the registration and scope rules.
Steps Live in the URL¶
The base WizardView keeps the current step in storage behind a single URL, and only NamedUrlWizardView exposes it.
The FormWizard always resolves the current step from the URL segment, so bookmarks and the browser back button work by construction.
There is no {{ wizard.management_form }} and no wizard_goto_step POST field.
Navigation to an earlier step is a plain link to its URL, built with wizard.goto(step).
done Receives Data, Not Forms¶
formtools revalidates every form at the end and passes the instances into done.
The FormWizard persists each step’s cleaned data through the backend as it validates, then passes one merged dict.
Per-step access goes through get_cleaned_data_for_step.
A field declared by two steps merges to the last stored value, and the next.W059 system check warns about such collisions.
Validation Re-Render Is Free¶
An invalid step re-renders the page with the bound failing form under the same form variable the template already uses.
There is no per-step template selection and no {{ wizard.form }} indirection, the one {% form %} block covers every step.
Files in Steps¶
formtools supports uploads inside steps through file_storage.
The FormWizard has no file_storage equivalent.
Wizard storage persists cleaned data between requests, and an uploaded file does not survive that round trip, so the next.W058 system check warns when a static step declares a FileField.
Collect the upload in a standalone form action instead, see Handle File Uploads.
Verification¶
Run the system checks after the port.
uv run python manage.py check
next.E050 catches an empty step list, next.W057 a step class doubling as a standalone action, next.W058 a file field in a step, and next.W059 a field declared by two steps.
Then walk the flow once: fill the first step, use the browser back button to confirm the draft reappears, and finish to confirm done runs exactly once.
See Also¶
See also
Form Wizards for the full wizard topic guide. Wizard Backend for the storage backends. Build a Multi-Step Wizard for the step-by-step recipe. System Checks for the check conditions.