python
48 lines · 10 steps
A multi-step signup wizard in Flask
A Flask Blueprint spreads a signup form across two steps, stashing each step's data in the session until the account is created.
Explained by
highlit
1from flask import Blueprint, render_template, redirect, url_for, session, request
2from wtforms import Form, StringField, SelectField, IntegerField
3from wtforms.validators import DataRequired, Email, NumberRange
4
5signup = Blueprint("signup", __name__, url_prefix="/signup")
6
7
8class AccountForm(Form):
9 full_name = StringField("Full name", validators=[DataRequired()])
10 email = StringField("Email", validators=[DataRequired(), Email()])
11
12
13class PlanForm(Form):
14 plan = SelectField("Plan", choices=[("free", "Free"), ("pro", "Pro")])
15 seats = IntegerField("Seats", validators=[NumberRange(min=1, max=50)])
16
17
18def _wizard():
19 return session.setdefault("signup_wizard", {})
20
21
22@signup.route("/step-1", methods=["GET", "POST"])
23def step_one():
24 form = AccountForm(request.form, data=_wizard())
25 if request.method == "POST" and form.validate():
26 _wizard().update(form.data)
27 session.modified = True
28 return redirect(url_for("signup.step_two"))
29 return render_template("signup/step_1.html", form=form)
30
31
32@signup.route("/step-2", methods=["GET", "POST"])
33def step_two():
34 if not _wizard().get("email"):
35 return redirect(url_for("signup.step_one"))
36
37 form = PlanForm(request.form, data=_wizard())
38 if request.method == "POST" and form.validate():
39 _wizard().update(form.data)
40 user = User.create_from_wizard(session.pop("signup_wizard"))
41 session.modified = True
42 return redirect(url_for("dashboard.home", welcome=user.id))
43 return render_template("signup/step_2.html", form=form)
44
45
46@signup.route("/back")
47def back():
48 return redirect(url_for("signup.step_one"))
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Storing intermediate form data in the session lets a single workflow span multiple requests and pages.
- 2Guarding later steps against missing earlier data keeps users from skipping ahead via direct URLs.
- 3A Blueprint groups related routes under one URL prefix so a feature stays self-contained.
Related explainers
python
class Parser: def __init__(self, text): self.tokens = self._tokenize(text) self.pos = 0
A recursive descent arithmetic parser
recursive-descent
tokenizer
operator-precedence
Intermediate
9 steps
python
import re from dataclasses import dataclass, field
Building a table of contents from Markdown
regular-expressions
parsing
slugification
Intermediate
9 steps
python
from itertools import cycle from collections import defaultdict
Round-robin task distribution in Python
round-robin
iterators
load-balancing
Intermediate
6 steps
python
import base64 import json from typing import Annotated, Optional
Cursor pagination in a FastAPI endpoint
pagination
cursor
async
Intermediate
9 steps
python
import secrets from fastapi import Depends, FastAPI, HTTPException, Security, status from fastapi.security import APIKeyHeader
API key authentication as a FastAPI dependency
authentication
dependency-injection
api-keys
Intermediate
8 steps
python
import hashlib from collections import defaultdict from pathlib import Path
Finding duplicate files by size then hash
hashing
file-io
deduplication
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/a-multi-step-signup-wizard-in-flask-explained-python-d7a5/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.