Flash Messages#
Flash messages are used to display informational, warning, or error messages to the user.
They are especially useful for reporting success or validation errors after form submissions.
⚠️ Important: Flash messages require the CherryPy sessions tool to be enabled, as messages are stored in the user session.
How It Works#
Storage: Flash messages are stored in the user’s session under the
flashkeyRetrieval:
get_flashed_messages()retrieves all messages and clears them from the sessionOne-time display: Messages are automatically removed after being retrieved, ensuring they only display once
This makes flash messages perfect for post-redirect-get patterns where you want to show a message after a form submission.
Setup#
1. Enable Sessions and Configure Jinja2#
import cherrypy
from cherrypy_foundation.flash import get_flashed_messages
# Create Jinja2 environment with get_flashed_messages available
env = cherrypy.tools.jinja2.create_env(
package_name=__package__,
globals={'get_flashed_messages': get_flashed_messages},
)
@cherrypy.tools.sessions(locking='explicit') # Required for flash messages
@cherrypy.tools.jinja2(env=env)
class Root:
pass
2. Display Messages in Templates#
Call get_flashed_messages() in your Jinja2 template to retrieve and display flash messages:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
</head>
<body>
<!-- Display flash messages -->
{% for message in get_flashed_messages() %}
<div class="alert alert-{{ message.level }} alert-dismissible fade show">
{{ message.message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endfor %}
<!-- Page content -->
<h1>Welcome!</h1>
</body>
</html>
Usage#
Adding Flash Messages#
Use the flash() function to add messages in your handler:
from cherrypy_foundation.flash import flash
@cherrypy.expose
def save_profile(self, **kwargs):
# Save user profile...
flash('Profile updated successfully!', level='success')
raise cherrypy.HTTPRedirect('/profile')
Message Levels#
Flash messages support four severity levels:
info- Informational messages (default)success- Success confirmationswarning- Warning messageserror- Error messages
flash('Account created successfully', level='success')
flash('Please verify your email address', level='info')
flash('Your session will expire in 5 minutes', level='warning')
flash('Failed to save changes', level='error')
HTML Markup Support#
Flash messages support both plain strings and HTML markup:
from markupsafe import Markup
# Plain text
flash('Simple message', level='info')
# HTML markup (safe HTML)
flash(Markup('Click <a href="/help">here</a> for help'), level='info')
Using the JinjaX Flash Component#
If you have JinjaX installed, you can use the built-in <Flash /> component for easier rendering:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<Flash
messages="{{ get_flashed_messages() }}"
class="mb-2"
style="min-height: 100px"
/>
<h1>Welcome!</h1>
</body>
</html>
The <Flash /> component automatically handles:
Rendering messages with appropriate Bootstrap alert classes
Dismiss buttons for each message
Custom styling via
classandstyleattributes
Complete Example#
import cherrypy
import cherrypy_foundation.tools.jinja2
from cherrypy_foundation.flash import flash, get_flashed_messages
# Setup Jinja2
env = cherrypy.tools.jinja2.create_env(
package_name=__package__,
globals={'get_flashed_messages': get_flashed_messages},
)
@cherrypy.tools.sessions(locking='explicit')
@cherrypy.tools.jinja2(env=env)
class Root:
@cherrypy.expose
@cherrypy.tools.jinja2(template='index.html')
def index(self):
return {}
@cherrypy.expose
def submit(self, name=None):
if not name:
flash('Name is required', level='error')
else:
flash(f'Welcome, {name}!', level='success')
raise cherrypy.HTTPRedirect('/')
if __name__ == '__main__':
cherrypy.quickstart(Root())
Template: form.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Registration Form</title>
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-5">
<!-- Flash messages -->
{% for message in get_flashed_messages() %}
<div class="alert alert-{{ message.level }} alert-dismissible">
{{ message.message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endfor %}
<!-- Form -->
<form method="post" action="/submit">
<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input type="text" class="form-control" id="name" name="name">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>