Flask redirect with error/success message

Viewed 256

In flask, how do you implement a redirect while passing some sort of variable to add a message to the subsequent html?

This is an example from CS50's finance website's index page.

Notice how in the first html, there's no header tags, but when the user is in the '/buy' route and clicks 'buy', they get redirected back to the '/' route, this time with a header.

I'm assuming when the user clicks 'buy' the python looks something like:

@app.route('/buy', methods = ['GET', 'POST'])
def buy():
if request.method == 'POST':
    # Code
    return redirect('/') # Plus something to pass the header message
return render_template('buy.html')

I already know about using redirect() and url_for() together but I'd prefer if there's a way to do this without changing the URL address.

Thanks for any help in advance!

1 Answers

The message on the form submission can be shown using the message flushing when redirecting a user to the same or to a different page. Message flashing documentation can be found in Flask example of message flashing.

Here I have shown an example of a filtered message flashing with success and error scenarios. Suppose, we have a checkout form where we have 5 products in stock. When a user selects more than 5 products we show an error message to the user. Otherwise, we show a success message. I used bootstrap 5 for the design. Initially, there was no message on the page. When the user selects the number of products and submits the form then the user is redirected to the same page and shows a message based on the number of products. If the user selects more than 5 products, the user sees an error message. Otherwise, the user sees a success message.

app.py:

from flask import Flask, render_template, flash, url_for, request, redirect

app = Flask(__name__)
app.secret_key = b'a secret key'

@app.route('/buy', methods=['GET', 'POST'])
def buy():
    if request.method == 'POST':
        quantity = int(request.form['product_quantity'])
        if quantity > 5:
            flash('Out of stock! We have only 5 products in stock.', 'error')
        else:
            flash(f'Bought {quantity} items successfully!', 'success')
        return redirect(url_for('buy'))
    return render_template('buy.html')

buy.html:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Flask Flash Demo</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css"
          rel="stylesheet"
          integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor"
          crossorigin="anonymous">
</head>
<body>
<main>
    <div class="container">
        <div class="py-5 text-center">
            <h2>Checkout form</h2>
            <p class="lead">Below is an example form to show filtered flash
                messages using Flask. This example include two categories:
                <mark>success</mark>
                and
                <mark>error</mark>
                . Change the quantity from
                the dropdown in form submit to check the flash messages. The
                message box can be closed using the cross icon on upper right
                corner.
            </p>
        </div>
        {% with errors = get_flashed_messages(category_filter=["error"]) %}
        {% if errors %}
        <div class="alert alert-danger alert-dismissible fade show"
             role="alert">
            <ul>
                {%- for msg in errors %}
                <li>{{ msg }}</li>
                {% endfor -%}
            </ul>

            <button type="button" class="btn-close" data-bs-dismiss="alert"
                    aria-label="Close"></button>
        </div>
        {% endif %}
        {% endwith %}

        {% with messages = get_flashed_messages(category_filter=["success"]) %}
        {% if messages %}
        <div class="alert alert-success alert-dismissible fade show"
             role="alert">
            <ul>
                {%- for msg in messages %}
                <li>{{ msg }}</li>
                {% endfor -%}
            </ul>

            <button type="button" class="btn-close" data-bs-dismiss="alert"
                    aria-label="Close"></button>
        </div>
        {% endif %}
        {% endwith %}
        <form method="post">
            <div class="mb-3">
                <label for="product_quantity" class="form-label">Product
                    quantity</label>
                <select name="product_quantity" class="form-select"
                        id="product_quantity">
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                    <option value="5">5</option>
                    <option value="10">10</option>
                    <option value="20">20</option>
                    <option value="30">30</option>
                </select>
            </div>
            <button type="submit" class="btn btn-primary">Submit</button>
        </form>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js"
            integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2"
            crossorigin="anonymous"></script>
</main>
</body>
</html>

Demo:

  • Message flashing using success filter when a user selects less or equal than 5 products: Message flashing using success filter

  • Message flashing using error filter when a user selects more than 5 products: Message flashing using error filter

References:

Related