Flask
Tutorial Flask: Flash messages
Aprende a usar mensajes flash en Flask para mostrar feedback temporal con categorías y estilos, mejorando la experiencia de usuario en tus aplicaciones web.
Aprende Flask y certifícateSistema de mensajes flash
Los mensajes flash en Flask proporcionan una forma elegante de mostrar información temporal al usuario después de realizar una acción específica. Este sistema permite almacenar mensajes en la sesión del usuario y mostrarlos en la siguiente petición, siendo especialmente útil para proporcionar feedback inmediato tras el envío de formularios.
Flask incluye de forma nativa la función flash()
que permite almacenar mensajes temporales. Estos mensajes se mantienen disponibles únicamente para la próxima petición, después de la cual se eliminan automáticamente. Esta característica los convierte en la solución ideal para notificar al usuario sobre el resultado de operaciones como crear, actualizar o eliminar registros.
Configuración básica de mensajes flash
Para utilizar mensajes flash, tu aplicación Flask debe tener configurada una clave secreta. Esta clave es necesaria porque Flask utiliza las sesiones para almacenar temporalmente los mensajes:
from flask import Flask
app = Flask(__name__)
app.secret_key = 'tu_clave_secreta_aqui'
Una vez configurada la clave secreta, puedes usar la función flash()
en cualquier ruta de tu aplicación. La función acepta el mensaje como primer parámetro:
from flask import flash, redirect, url_for
@app.route('/crear-usuario', methods=['POST'])
def crear_usuario():
# Lógica para crear usuario
usuario_creado = True
if usuario_creado:
flash('Usuario creado exitosamente')
return redirect(url_for('lista_usuarios'))
else:
flash('Error al crear el usuario')
return redirect(url_for('formulario_usuario'))
Mostrar mensajes en plantillas Jinja
Para mostrar los mensajes flash en tus plantillas, Flask proporciona la función get_flashed_messages()
que está disponible automáticamente en el contexto de Jinja. Esta función devuelve una lista con todos los mensajes flash pendientes:
<!-- En tu plantilla base.html -->
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="flash-messages">
{% for message in messages %}
<div class="alert">
{{ message }}
</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
También puedes usar una sintaxis más directa si prefieres iterar directamente sobre los mensajes:
{% for message in get_flashed_messages() %}
<div class="notification">
<p>{{ message }}</p>
</div>
{% endfor %}
Integración con formularios WTForms
Los mensajes flash se integran perfectamente con WTForms para proporcionar feedback después de la validación y procesamiento de formularios. Aquí tienes un ejemplo práctico:
from flask import render_template, flash, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
class ProductoForm(FlaskForm):
nombre = StringField('Nombre del producto', validators=[DataRequired()])
submit = SubmitField('Guardar')
@app.route('/productos/nuevo', methods=['GET', 'POST'])
def nuevo_producto():
form = ProductoForm()
if form.validate_on_submit():
# Procesar datos del formulario
nombre_producto = form.nombre.data
# Simular guardado en base de datos
producto_guardado = guardar_producto(nombre_producto)
if producto_guardado:
flash(f'Producto "{nombre_producto}" creado correctamente')
return redirect(url_for('lista_productos'))
else:
flash('Error al guardar el producto. Inténtalo de nuevo')
return render_template('nuevo_producto.html', form=form)
En la plantilla correspondiente, puedes mostrar tanto los mensajes flash como los errores de validación del formulario:
<!-- nuevo_producto.html -->
{% extends "base.html" %}
{% block content %}
<!-- Mostrar mensajes flash -->
{% for message in get_flashed_messages() %}
<div class="alert alert-info">
{{ message }}
</div>
{% endfor %}
<form method="POST">
{{ form.hidden_tag() }}
<div class="form-group">
{{ form.nombre.label(class="form-label") }}
{{ form.nombre(class="form-control") }}
<!-- Mostrar errores de validación -->
{% if form.nombre.errors %}
{% for error in form.nombre.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
{{ form.submit(class="btn btn-primary") }}
</form>
{% endblock %}
Patrón POST-Redirect-GET
Los mensajes flash funcionan especialmente bien con el patrón POST-Redirect-GET (PRG), que es una práctica recomendada en aplicaciones web. Este patrón evita que los usuarios reenvíen accidentalmente formularios al actualizar la página:
@app.route('/editar-producto/<int:id>', methods=['GET', 'POST'])
def editar_producto(id):
producto = obtener_producto(id)
form = ProductoForm(obj=producto)
if form.validate_on_submit():
# Actualizar producto con datos del formulario
producto.nombre = form.nombre.data
if actualizar_producto(producto):
flash('Producto actualizado correctamente')
# Redirección después del POST exitoso
return redirect(url_for('detalle_producto', id=producto.id))
else:
flash('Error al actualizar el producto')
# Mostrar formulario en peticiones GET o POST inválidas
return render_template('editar_producto.html', form=form, producto=producto)
Este enfoque garantiza que los mensajes flash se muestren correctamente después de operaciones exitosas, mientras que los errores de validación se mantienen en la misma página para que el usuario pueda corregirlos inmediatamente.
Categorías de mensajes
Flask permite organizar los mensajes flash mediante categorías, proporcionando una forma de clasificar los mensajes según su propósito o nivel de importancia. Esta funcionalidad resulta especialmente útil para aplicar diferentes estilos visuales y comportamientos según el tipo de mensaje que se desea mostrar al usuario.
Definición de categorías en mensajes flash
La función flash()
acepta un segundo parámetro opcional que especifica la categoría del mensaje. Si no se proporciona ninguna categoría, Flask asigna automáticamente la categoría 'message'
por defecto:
from flask import flash
# Mensaje sin categoría (categoría 'message' por defecto)
flash('Operación completada')
# Mensajes con categorías específicas
flash('Usuario creado exitosamente', 'success')
flash('Campos obligatorios sin completar', 'error')
flash('Los cambios se guardarán automáticamente', 'info')
flash('Esta acción no se puede deshacer', 'warning')
Las categorías más comunes en aplicaciones web incluyen success
, error
, warning
e info
, aunque puedes definir cualquier nombre de categoría que se adapte a las necesidades de tu aplicación.
Recuperación de mensajes por categoría
Para trabajar con mensajes categorizados en las plantillas, la función get_flashed_messages()
ofrece varios parámetros que permiten filtrar y organizar los mensajes:
# En el controlador, enviamos mensajes de diferentes categorías
@app.route('/procesar-pedido', methods=['POST'])
def procesar_pedido():
form = PedidoForm()
if form.validate_on_submit():
try:
pedido = crear_pedido(form.data)
flash('Pedido creado correctamente', 'success')
flash('Recibirás un email de confirmación', 'info')
except StockInsuficienteError:
flash('Algunos productos no tienen stock suficiente', 'warning')
except Exception:
flash('Error al procesar el pedido', 'error')
return redirect(url_for('resumen_pedido'))
En las plantillas Jinja, puedes recuperar mensajes específicos por categoría utilizando el parámetro category_filter
:
<!-- Mostrar solo mensajes de error -->
{% for message in get_flashed_messages(category_filter=['error']) %}
<div class="alert alert-danger">
<strong>Error:</strong> {{ message }}
</div>
{% endfor %}
<!-- Mostrar mensajes de éxito e información -->
{% for message in get_flashed_messages(category_filter=['success', 'info']) %}
<div class="alert alert-success">
{{ message }}
</div>
{% endfor %}
Acceso a categorías junto con mensajes
Para obtener tanto el mensaje como su categoría, utiliza el parámetro with_categories=True
. Este parámetro hace que get_flashed_messages()
devuelva una lista de tuplas donde cada tupla contiene la categoría y el mensaje:
{% for category, message in get_flashed_messages(with_categories=true) %}
<div class="alert alert-{{ category }}">
{% if category == 'error' %}
<i class="icon-error"></i>
{% elif category == 'success' %}
<i class="icon-check"></i>
{% elif category == 'warning' %}
<i class="icon-warning"></i>
{% else %}
<i class="icon-info"></i>
{% endif %}
{{ message }}
</div>
{% endfor %}
Implementación práctica con estilos CSS
Una implementación común consiste en mapear las categorías de mensajes con clases CSS específicas para crear una experiencia visual coherente:
<!-- En tu plantilla base -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class="flash-container">
{% for category, message in messages %}
<div class="flash-message flash-{{ category }}">
<span class="flash-icon">
{% if category == 'success' %}✓{% endif %}
{% if category == 'error' %}✗{% endif %}
{% if category == 'warning' %}⚠{% endif %}
{% if category == 'info' %}ℹ{% endif %}
</span>
<span class="flash-text">{{ message }}</span>
</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
El CSS correspondiente podría definir estilos específicos para cada categoría:
.flash-message {
padding: 12px 16px;
margin: 8px 0;
border-radius: 4px;
display: flex;
align-items: center;
}
.flash-success {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.flash-error {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.flash-warning {
background-color: #fff3cd;
color: #856404;
border: 1px solid #ffeaa7;
}
.flash-info {
background-color: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
Ejemplo completo con formulario WTForms
Aquí tienes un ejemplo que integra categorías de mensajes con la validación de formularios:
@app.route('/configuracion/perfil', methods=['GET', 'POST'])
def actualizar_perfil():
form = PerfilForm()
if form.validate_on_submit():
try:
usuario = obtener_usuario_actual()
# Verificar si el email ya existe
if form.email.data != usuario.email:
if email_existe(form.email.data):
flash('El email ya está en uso por otro usuario', 'warning')
return render_template('perfil.html', form=form)
# Actualizar datos
usuario.nombre = form.nombre.data
usuario.email = form.email.data
guardar_usuario(usuario)
flash('Perfil actualizado correctamente', 'success')
flash('Los cambios pueden tardar unos minutos en aplicarse', 'info')
return redirect(url_for('ver_perfil'))
except ValidationError as e:
flash(f'Error de validación: {str(e)}', 'error')
except Exception:
flash('Error interno del servidor. Inténtalo más tarde', 'error')
return render_template('perfil.html', form=form)
Esta aproximación permite crear una experiencia de usuario más rica y informativa, donde cada tipo de mensaje transmite claramente su propósito y urgencia mediante el uso apropiado de categorías y estilos visuales diferenciados.
Otras lecciones de Flask
Accede a todas las lecciones de Flask y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Flask
Introducción Y Entorno
Instalación Y Configuración Flask Con Venv
Introducción Y Entorno
Rutas Endpoints Rest Get
Api Rest
Respuestas Con Esquemas Flask Marshmallow
Api Rest
Rutas Endpoints Rest Post, Put Y Delete
Api Rest
Manejo De Errores Y Códigos De Estado Http
Api Rest
Ejercicios de programación de Flask
Evalúa tus conocimientos de esta lección Flash messages con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.