Flask Session y Cookie
El protocolo HTTP en sí mismo no tiene estado: el servidor no recuerda automáticamente si dos solicitudes provienen del mismo usuario.
Flask, medianteSessionel mecanismo, resuelve este problema, permitiendo que las aplicaciones web puedan «recordar» el estado del usuario.
Cómo funciona Session
Flask usa de forma predeterminadaSecureCookieSessionsu modo de funcionamiento es:
- Los datos de Session se serializan, se firman con una clave y se guardan en la Cookie del navegador.
- En cada solicitud, el navegador envía automáticamente esta Cookie.
- Flask, después de verificar la firma, restaura los datos a un diccionario de Python para que los uses.
Los usuarios pueden ver el contenido de la Cookie (porque está codificada en base64), pero no pueden modificarla, ya que cualquier cambio provocaría que la verificación de la firma fallara.
Configurar SECRET_KEY
Para usar Session, primero debes configurarSECRET_KEY—la clave utilizada para firmar.
Ejemplo
from flask import Flask
app = Flask(__name__)
# Genera una clave aleatoria segura (solo necesita generarse en la primera ejecución)
# secrets.token_hex() produce una cadena hexadecimal aleatoria de 64 caracteres
app.secret_key = secrets.token_hex()
# O simplemente establece un valor fijo (conveniente para desarrollo, pero no lo uses en producción)
# app.secret_key = "dev-secret-key-change-in-production"
Importante:SECRET_KEYSECRET_KEY debe mantenerse en secreto y ser suficientemente aleatoria. Si la clave se filtra, cualquiera puede falsificar los datos de Session de tu aplicación. En producción, debe leerse desde variables de entorno o archivos de configuración; no la hardcodees en el código.
Comando para generar una clave de alta calidad:
$ python -c 'import secrets; print(secrets.token_hex())' 192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf
Leer y escribir Session
sessionsession es un objeto similar a un diccionario; su uso es básicamente igual al de un diccionario de Python:
Ejemplo
app = Flask(__name__)
app.secret_key = "dev-secret-key"
@app.route("/")
def index():
# Comprueba si hay un username en session
if "username" in session:
return f"""
<h1>¡Bienvenido de nuevo, {session["username"]}!</h1>
<p>Tus visitas: {session.get("visits", 0)}</p>
<p><a href="/logout">Cerrar sesión</a></p>
"""
return """
<h1>Página de inicio de EJEMPLO</h1>
<p>Aún no has iniciado sesión.</p>
<p><a href="/login">Ir a iniciar sesión</a></p>
"""
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form.get("username", "")
if username:
# Guarda el nombre de usuario en session
session["username"] = username
# Inicializa el contador de visitas
session["visits"] = 0
return redirect(url_for("index"))
return """
<form method="post">
<h2>Iniciar sesión en EJEMPLO</h2>
<p><input type="text" name="username" placeholder="Introduce tu nombre de usuario"></p>
<p><input type="submit" value="Iniciar sesión"></p>
</form>
"""
@app.route("/logout")
def logout():
# Elimina todos los datos de session
session.clear()
# O elimina solo una clave específica:
# session.pop("username", None)
return redirect(url_for("index"))
Session permanente
De forma predeterminada, Session caduca cuando se cierra el navegador (a nivel de sesión del navegador).
Si necesitas la función «recordarme», puedes marcar Session comopermanente:
Ejemplo
# Establece la validez de la session permanente (31 días por defecto)
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(days=7)
@app.post("/login-remember")
def login_remember():
username = request.form.get("username")
if username:
session["username"] = username
# Márcala como session permanente; seguirá siendo válida después de cerrar el navegador
session.permanent = True
return redirect(url_for("index"))
Message Flashing: mensajes de una sola vez
Después de que el usuario envía un formulario, es necesario mostrar un mensaje de retroalimentación como «operación exitosa» o «error».
Para este tipo de mensajes que «desaparecen después de mostrarse una vez», Flask proporcionaflash()el mecanismo.
Ejemplo
app = Flask(__name__)
app.secret_key = "dev-secret-key"
@app.route("/post", methods=["GET", "POST"])
def create_post():
if request.method == "POST":
title = request.form.get("title", "").strip()
if not title:
# Guarda el mensaje de error en flash, con categoría "error"
flash("El título no puede estar vacío", "error")
return redirect(url_for("create_post"))
# Guarda el mensaje de éxito en flash, con categoría "success"
flash(f"¡El artículo «{title}» se publicó con éxito!", "success")
return redirect(url_for("create_post"))
return render_template("create_post.html")
@app.route("/flash-demo")
def flash_demo():
# Obtiene todos los mensajes flash (se eliminan automáticamente al leerlos)
messages = get_flashed_messages(with_categories=True)
return render_template("flash_demo.html", messages=messages)
Renderizar mensajes flash en la plantilla:
Ejemplo
<!DOCTYPE html>
<html>
<head>
<title>Publicar artículo - EJEMPLO</title>
<style>
.flash-success { color: green; background: #E8EEF5; padding: 10px; border-radius: 4px; }
.flash-error { color: red; background: #ffebee; padding: 10px; border-radius: 4px; }
.flash-info { color: blue; background: #e3f2fd; padding: 10px; border-radius: 4px; }
</style>
</head>
<body>
<h1>Publicar artículo</h1>
<!-- Obtener y mostrar todos los mensajes flash -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="flash-{{ category }}">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
<form method="post">
<p>Título:<input type="text" name="title" style="width:300px;"></p>
<p><input type="submit" value="Publicar"></p>
</form>
</body>
</html>
| Categoría | Escenarios de uso recomendados |
|---|---|
| "message" (predeterminado) | Notificación general |
| "success" | Operación exitosa |
| "error" | Operación fallida |
| "warning" | Mensaje de advertencia |
| "info" | Información general |
Los mensajes Flash dependen de Session, por lo que debes configurarSECRET_KEYpara poder utilizarlos.
Preguntas frecuentes sobre Session
Otras extensionesLímite de tamaño de Cookie: el navegador limita el tamaño de una Cookie individual a aproximadamente 4KB. No almacenes grandes cantidades de datos en Session; es adecuada para información ligera como ID de usuario o preferencias, pero no para archivos u objetos grandes.