I will try to simplify with general steps so that you can apply it to say shopping as easily as possible and to make the code more readable.
Code structure:
.
├── app.py
└── templates
├── finish.html
└── step.html
Below I will provide the code for each of the files:
from flask import Flask, render_template, redirect, url_for, request, session
from flask_bootstrap import Bootstrap
from wtforms import StringField, TextAreaField, SubmitField
from wtforms.validators import InputRequired
from flask_wtf import FlaskForm
app = Flask(__name__)
app.secret_key = 'secret'
bootstrap = Bootstrap(app)
class StepOneForm(FlaskForm):
title = 'Step One'
name = StringField('Name', validators=[InputRequired()])
submit = SubmitField('Next')
class StepTwoForm(FlaskForm):
title = 'Step Two'
email = StringField('Email', validators=[InputRequired()])
submit = SubmitField('Next')
class StepThreeForm(FlaskForm):
title = 'Step Three'
address = TextAreaField('Address', validators=[InputRequired()])
submit = SubmitField('Next')
class StepFourForm(FlaskForm):
title = 'Step Four'
phone = StringField('Phone', validators=[InputRequired()])
submit = SubmitField('Finish')
@app.route('/')
def index():
return redirect(url_for('step', step=1))
@app.route('/step/<int:step>', methods=['GET', 'POST'])
def step(step):
forms = {
1: StepOneForm(),
2: StepTwoForm(),
3: StepThreeForm(),
4: StepFourForm(),
}
form = forms.get(step, 1)
if request.method == 'POST':
if form.validate_on_submit():
# Save form data to session
session['step{}'.format(step)] = form.data
if step < len(forms):
# Redirect to next step
return redirect(url_for('step', step=step+1))
else:
# Redirect to finish
return redirect(url_for('finish'))
# If form data for this step is already in the session, populate the form with it
if 'step{}'.format(step) in session:
form.process(data=session['step{}'.format(step)])
content = {
'progress': int(step / len(forms) * 100),
'step': step,
'form': form,
}
return render_template('step.html', **content)
@app.route('/finish')
def finish():
data = {}
for key in session.keys():
if key.startswith('step'):
data.update(session[key])
session.clear()
return render_template('finish.html', data=data)
if __name__ == '__main__':
app.run(debug=True)
{% extends 'bootstrap/base.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-8 offset-md-2">
<h1>Finish</h1>
<p>Thank you for your submission!</p>
<table class="table">
{% for key, value in data.items() %}
{% if key not in ['csrf_token', 'submit', 'previous']%}
<tr>
<th>{{ key }}</th>
<td>{{ value }}</td>
</tr>
{% endif %}
{% endfor %}
</table>
</div>
</div>
</div>
{% endblock %}
{% extends 'bootstrap/base.html' %}
{% import "bootstrap/wtf.html" as wtf %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-8 offset-md-2">
<div class="progress mb-4">
<div class="progress-bar" role="progressbar" style="width: {{ progress }}%" aria-valuenow="{{ progress }}" aria-valuemin="0" aria-valuemax="100">{{ form.title }}: {{ progress }}%</div>
</div>
<br>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<br>
<h3>{{ form.title.upper() }}</h3>
<hr>
{{ wtf.quick_form(form) }}
<br>
{% if step > 1 %}
<a href="{{ url_for('step', step=step-1) }}" class="btn btn-default">Previous</a>
{% endif %}
</div>
</div>
</div>
{% endblock %}
OUTPUT: