Search code examples
htmlflaskflash

How to use session to display flash message


I'm new to flask framework and trying to build an web application. Currently I'm trying to display a live toast notification by using the toast notification options. I have tried a lot of method but still can't make it. It there any way to solve it?

The toast notifications option in base.html

<script>
    //Toast notifications
    if(Session.has('message')){
        toastr.options = {
        "closeButton": true,
        "progressBar": true,
        "positionClass": "toast-bottom-right",
        "fadeIn": 300,
        "fadeOut": 1000,
        "timeOut": 5000,
        }
        //toastr.success("{{ session('message') }}");
    }
</script>

The session in app.py. When the user register successfully, it will redirect the user to login page and display the toast notification message to the user.

@app.route('/register',methods=['GET','POST'])
def register():
form = UserForm(request.form)
if request.method == 'POST' and form.validate():
    hashed_pw = generate_password_hash(form.password.data,"sha256")
    with sql.connect("database.db") as conn:
        cur = conn.cursor()
        cur.execute("INSERT INTO User (first_name, last_name, email, password, type) VALUES (?,?,?,?,'customer')",(form.first_name.data, form.last_name.data, form.email.data, hashed_pw))

        conn.commit()
    session ['name'] = form.first_name.data + form.last_name.data
    flash("{session['name']} has been registered successfully") 
    return redirect(url_for('login'))
return render_template('register.html', form = form)

This is the problem that I always met when doing the toast notification

127.0.0.1 - - [23/Nov/2022 03:50:17] "GET / HTTP/1.1" 200 -
[2022-11-23 03:50:19,220] ERROR in app: Exception on /register [GET]
Traceback (most recent call last):
File "C:\Users\user\desktop\phonebuddy\.venv\lib\site-packages\flask\app.py", line 2525, in 
wsgi_app
response = self.full_dispatch_request()
File "C:\Users\user\desktop\phonebuddy\.venv\lib\site-packages\flask\app.py", line 1822, in 
full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\user\desktop\phonebuddy\.venv\lib\site-packages\flask\app.py", line 1820, in 
full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\user\desktop\phonebuddy\.venv\lib\site-packages\flask\app.py", line 1796, in 
dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "C:\Users\user\Desktop\PhoneBuddy\app.py", line 55, in register
return render_template('register.html', form = form)
File "C:\Users\user\desktop\phonebuddy\.venv\lib\site-packages\flask\templating.py", line 147, 
in render_template
return _render(app, template, context)
File "C:\Users\user\desktop\phonebuddy\.venv\lib\site-packages\flask\templating.py", line 130, 
in _render
rv = template.render(context)
File "C:\Users\user\desktop\phonebuddy\.venv\lib\site-packages\jinja2\environment.py", line 
1301, in render
self.environment.handle_exception()
File "C:\Users\user\desktop\phonebuddy\.venv\lib\site-packages\jinja2\environment.py", line 
936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "C:\Users\user\Desktop\PhoneBuddy\templates\register.html", line 1, in top-level template 
code
{% extends 'base.html' %}
File "C:\Users\user\Desktop\PhoneBuddy\templates\base.html", line 82, in top-level template 
code
<!--toastr.success("{{ session('message') }}");-->
TypeError: 'SecureCookieSession' object is not callable
127.0.0.1 - - [23/Nov/2022 03:50:19] "GET /register HTTP/1.1" 500 -

Solution

  • The error message is related to the wrong parentheses you are using within the call in the template. Using the session is like querying a dict. So use session[key] or session.get(key), whereby the second option allows you to specify a default value.

    Below is a small example of using toastr for message flashing in flask.

    from flask import ( 
        Flask, 
        render_template, 
        request, 
        flash
    )
    
    app = Flask(__name__)
    app.secret_key = 'your secret here'
    
    @app.route('/', methods=['GET', 'POST'])
    def index():
        if request.method == 'POST':
            msg = request.form.get('msg')
            msg_type = request.form.get('msg-type', 'success')
            if msg:
                flash(msg, msg_type)
        return render_template('index.html')
    
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Index</title>
        <link 
            rel="stylesheet" 
            href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.css" 
            integrity="sha512-3pIirOrwegjM6erE5gPSwkUzO+3cTjpnV9lexlNZqvupR64iZBnOOTiiLPb9M36zpMScbmUNIcHUqKD47M719g==" 
            crossorigin="anonymous" 
            referrerpolicy="no-referrer" />
    </head>
    <body>
    
        <form method="post" style="display:grid; grid-gap: 0.6rem;">
            <label for="msg">Message</label>        
            <textarea name="msg" id="msg">This is a toastr notification.</textarea>
    
            <label for="msg-type">Toast Type</label>
            <select name="msg-type" id="msg-type">
                <option value="info">Info</option>
                <option value="success">Success</option>
                <option value="warning">Warning</option>
                <option value="error">Error</option>
            </select>
    
            <input type="submit" />
        </form>
    
        <script 
            src="https://code.jquery.com/jquery-3.6.1.min.js" 
            integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" 
            crossorigin="anonymous"></script>
        <script 
            src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js" 
            integrity="sha512-VEd+nq25CkR676O+pLBnDW09R7VQX9Mdiij052gVCp5yVH3jGtH70Ho/UUv4mJDsEdTvqRCFZg0NKGiojGnUCw==" 
            crossorigin="anonymous" 
            referrerpolicy="no-referrer"></script>
        <script type="text/javascript">
            (function() {
                toastr.options = {
                    "closeButton": true,
                    "progressBar": true,
                    "positionClass": "toast-bottom-right",
                    "fadeIn": 300,
                    "fadeOut": 1000,
                    "timeOut": 5000,
                }
                const msgs = {{ get_flashed_messages(with_categories=true) | tojson }};
                for (const [cat, msg] of msgs) {
                    toastr[cat](msg);
                }
            })()
        </script>
    
    </body>
    </html>