Mira la lección en vídeo
Accede al vídeo completo de esta lección y a más contenido exclusivo con el Plan Plus.
Desbloquear Plan PlusControladores GET
Los controladores GET en Flask representan el punto de entrada para manejar solicitudes HTTP GET dentro del patrón MVC. Estos controladores actúan como intermediarios entre las rutas definidas en tu aplicación y la lógica de negocio, coordinando la obtención de datos desde los modelos y su posterior presentación a través de las vistas.
En Flask, un controlador GET se implementa mediante funciones decoradas con @app.route()
que especifican el método HTTP permitido. La responsabilidad principal de estos controladores es procesar la solicitud entrante, interactuar con los modelos para obtener los datos necesarios y preparar la respuesta adecuada para el usuario.
Estructura básica de un controlador GET
Un controlador GET típico sigue una estructura predecible que facilita el mantenimiento y la comprensión del código:
from flask import Flask, render_template
from models import Usuario
app = Flask(__name__)
@app.route('/usuarios', methods=['GET'])
def listar_usuarios():
# Obtener datos del modelo
usuarios = Usuario.query.all()
# Preparar datos para la vista
datos_vista = {
'usuarios': usuarios,
'titulo': 'Lista de Usuarios'
}
# Renderizar la vista
return render_template('usuarios/lista.html', **datos_vista)
La separación de responsabilidades es fundamental en este enfoque. El controlador no debe contener lógica de presentación ni acceso directo a la base de datos más allá de las operaciones básicas del ORM.
Controladores con parámetros de ruta
Los controladores GET pueden recibir parámetros dinámicos a través de la URL, permitiendo crear rutas más flexibles y reutilizables:
@app.route('/usuario/<int:usuario_id>', methods=['GET'])
def mostrar_usuario(usuario_id):
# Buscar usuario específico
usuario = Usuario.query.get_or_404(usuario_id)
# Obtener datos relacionados
pedidos = usuario.pedidos.limit(5).all()
return render_template('usuarios/detalle.html',
usuario=usuario,
pedidos_recientes=pedidos)
Este patrón permite crear URLs semánticas que facilitan tanto la navegación del usuario como la indexación por motores de búsqueda. El uso de get_or_404()
garantiza que se maneje automáticamente el caso donde el recurso solicitado no existe.
Manejo de parámetros de consulta
Los controladores GET también pueden procesar parámetros de consulta (query parameters) para implementar funcionalidades como filtrado, paginación o búsqueda:
from flask import request
@app.route('/productos', methods=['GET'])
def listar_productos():
# Obtener parámetros de consulta
categoria = request.args.get('categoria', '')
pagina = request.args.get('pagina', 1, type=int)
por_pagina = 10
# Construir consulta base
query = Producto.query
# Aplicar filtros si existen
if categoria:
query = query.filter(Producto.categoria == categoria)
# Aplicar paginación
productos = query.paginate(
page=pagina,
per_page=por_pagina,
error_out=False
)
return render_template('productos/lista.html',
productos=productos,
categoria_actual=categoria)
Esta implementación demuestra cómo los controladores pueden procesar entrada del usuario de manera segura, aplicando validaciones y transformaciones necesarias antes de interactuar con los modelos.
Organización de controladores complejos
Para aplicaciones más grandes, es recomendable organizar los controladores en clases o módulos separados, manteniendo la cohesión funcional:
class UsuarioController:
@staticmethod
@app.route('/usuarios', methods=['GET'])
def index():
usuarios = Usuario.query.filter(Usuario.activo == True).all()
return render_template('usuarios/index.html', usuarios=usuarios)
@staticmethod
@app.route('/usuarios/<int:id>', methods=['GET'])
def show(id):
usuario = Usuario.query.get_or_404(id)
estadisticas = {
'total_pedidos': usuario.pedidos.count(),
'ultimo_acceso': usuario.ultimo_acceso
}
return render_template('usuarios/show.html',
usuario=usuario,
stats=estadisticas)
Esta aproximación facilita la reutilización de código y mejora la organización del proyecto, especialmente cuando se trabaja con múltiples desarrolladores o se mantiene una aplicación a largo plazo.
Manejo de errores en controladores GET
Los controladores deben implementar un manejo robusto de errores para proporcionar una experiencia de usuario consistente:
from flask import abort, flash, redirect, url_for
@app.route('/dashboard/<int:usuario_id>', methods=['GET'])
def dashboard_usuario(usuario_id):
try:
usuario = Usuario.query.get(usuario_id)
if not usuario:
abort(404)
# Verificar que el usuario tenga permisos
if not usuario.puede_ver_dashboard():
abort(403)
datos_dashboard = {
'usuario': usuario,
'resumen': usuario.obtener_resumen_actividad(),
'notificaciones': usuario.notificaciones_pendientes()
}
return render_template('dashboard.html', **datos_dashboard)
except Exception as e:
# Log del error para debugging
app.logger.error(f'Error en dashboard: {str(e)}')
flash('Error al cargar el dashboard', 'error')
return redirect(url_for('index'))
El manejo de excepciones debe ser específico y proporcionar retroalimentación útil tanto para el usuario final como para los desarrolladores durante el proceso de debugging.
render_template()
Guarda tu progreso
Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.
Más de 25.000 desarrolladores ya confían en CertiDevs
La función render_template() es el mecanismo principal que Flask proporciona para generar respuestas HTML dinámicas desde los controladores. Esta función actúa como el puente entre la lógica del controlador y las plantillas Jinja, permitiendo que los datos procesados en el backend se integren seamlessly en la presentación final que recibe el usuario.
render_template() forma parte del módulo flask
y debe importarse explícitamente para su uso. Su funcionamiento se basa en el motor de plantillas Jinja2, que Flask incluye por defecto, y busca las plantillas en el directorio templates/
de tu proyecto.
Sintaxis y parámetros básicos
La función acepta como primer parámetro el nombre del archivo de plantilla, seguido de argumentos con nombre que representan las variables que estarán disponibles en la plantilla:
from flask import Flask, render_template
@app.route('/bienvenida')
def bienvenida():
nombre_usuario = "María"
edad = 28
return render_template('bienvenida.html',
nombre=nombre_usuario,
edad=edad,
fecha_actual=datetime.now())
En este ejemplo, la plantilla bienvenida.html
tendrá acceso a las variables nombre
, edad
y fecha_actual
que podrá utilizar para generar contenido dinámico.
Paso de datos complejos
render_template() puede manejar estructuras de datos complejas, incluyendo listas, diccionarios y objetos del ORM:
@app.route('/tienda')
def mostrar_tienda():
productos = Producto.query.filter(Producto.disponible == True).all()
categorias = Categoria.query.all()
configuracion_tienda = {
'nombre': 'TechStore',
'moneda': 'EUR',
'descuento_activo': True,
'porcentaje_descuento': 15
}
return render_template('tienda/catalogo.html',
productos=productos,
categorias=categorias,
config=configuracion_tienda)
Las plantillas Jinja pueden iterar sobre las listas, acceder a propiedades de objetos y evaluar las condiciones basándose en estos datos, proporcionando gran flexibilidad en la presentación.
Uso del operador de desempaquetado
Para casos donde tienes un diccionario con múltiples variables, puedes utilizar el operador de desempaquetado (**
) para pasar todas las claves como argumentos con nombre:
@app.route('/perfil/<int:usuario_id>')
def perfil_usuario(usuario_id):
usuario = Usuario.query.get_or_404(usuario_id)
contexto = {
'usuario': usuario,
'total_pedidos': usuario.pedidos.count(),
'direcciones': usuario.direcciones.all(),
'favoritos': usuario.productos_favoritos.limit(5).all(),
'puede_editar': True
}
return render_template('usuarios/perfil.html', **contexto)
Este enfoque resulta especialmente útil cuando el contexto de datos es extenso o se construye dinámicamente, manteniendo el código del controlador más limpio y legible.
Organización de plantillas
Flask busca las plantillas siguiendo una estructura jerárquica dentro del directorio templates/
. Es recomendable organizar las plantillas en subdirectorios que reflejen la estructura lógica de tu aplicación:
# Estructura recomendada:
# templates/
# ├── base.html
# ├── usuarios/
# │ ├── lista.html
# │ ├── detalle.html
# │ └── formulario.html
# └── productos/
# ├── catalogo.html
# └── ficha.html
@app.route('/usuarios/<int:id>/editar')
def editar_usuario(id):
usuario = Usuario.query.get_or_404(id)
return render_template('usuarios/formulario.html',
usuario=usuario,
modo='edicion',
titulo='Editar Usuario')
Esta organización modular facilita el mantenimiento y permite que múltiples desarrolladores trabajen en diferentes secciones sin conflictos.
Manejo de plantillas condicionales
render_template() puede utilizarse para renderizar diferentes plantillas basándose en condiciones específicas, proporcionando flexibilidad en la presentación:
@app.route('/dashboard')
def dashboard():
usuario_actual = obtener_usuario_actual()
if usuario_actual.es_administrador():
datos = {
'usuarios_totales': Usuario.query.count(),
'pedidos_pendientes': Pedido.query.filter_by(estado='pendiente').count(),
'ingresos_mes': calcular_ingresos_mes()
}
return render_template('admin/dashboard.html', **datos)
else:
datos = {
'pedidos_usuario': usuario_actual.pedidos.limit(10).all(),
'direcciones': usuario_actual.direcciones.all()
}
return render_template('usuario/dashboard.html', **datos)
Este patrón permite personalizar la experiencia del usuario según su rol o características específicas, manteniendo la lógica de decisión en el controlador.
Integración con datos del ORM
La función trabaja eficientemente con objetos del ORM, permitiendo que las plantillas accedan directamente a las propiedades y relaciones de los modelos:
@app.route('/pedido/<int:pedido_id>')
def detalle_pedido(pedido_id):
pedido = Pedido.query.options(
db.joinedload(Pedido.usuario),
db.joinedload(Pedido.items).joinedload(ItemPedido.producto)
).get_or_404(pedido_id)
return render_template('pedidos/detalle.html',
pedido=pedido,
total_items=len(pedido.items),
puede_cancelar=pedido.puede_ser_cancelado())
Las plantillas Jinja pueden navegar por las relaciones del ORM (como pedido.usuario.nombre
o pedido.items
) sin necesidad de procesamiento adicional en el controlador, simplificando significativamente el código.
Optimización y buenas prácticas
Para aplicaciones con alto tráfico, es importante considerar la optimización del renderizado. Flask cachea automáticamente las plantillas compiladas, pero puedes optimizar el paso de datos:
@app.route('/catalogo')
def catalogo_productos():
# Consulta optimizada con select específico
productos = db.session.query(
Producto.id,
Producto.nombre,
Producto.precio,
Producto.imagen_url
).filter(Producto.activo == True).all()
# Preparar solo los datos necesarios
productos_vista = [
{
'id': p.id,
'nombre': p.nombre,
'precio_formateado': f"{p.precio:.2f}€",
'imagen': p.imagen_url or '/static/img/default.jpg'
}
for p in productos
]
return render_template('productos/catalogo.html',
productos=productos_vista,
total_productos=len(productos_vista))
Esta aproximación reduce la carga en la plantilla y mejora el rendimiento al procesar únicamente los datos que realmente se van a mostrar al usuario.
Aprendizajes de esta lección de Flask
- Comprender la función y estructura de los controladores GET en Flask dentro del patrón MVC.
- Aprender a manejar parámetros de ruta y de consulta para crear rutas dinámicas y funcionales.
- Utilizar render_template() para generar respuestas HTML dinámicas con datos del backend.
- Organizar controladores y plantillas para mantener un código limpio y modular.
- Implementar manejo de errores robusto en controladores para mejorar la experiencia de usuario.
Completa este curso de Flask y certifícate
Únete a nuestra plataforma de cursos de programación y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.
Asistente IA
Resuelve dudas al instante
Ejercicios
Practica con proyectos reales
Certificados
Valida tus conocimientos
Más de 25.000 desarrolladores ya se han certificado con CertiDevs