50% OFF Plus
--:--:--
¡Obtener!

Controlador MVC con métodos GET en Flask

Intermedio
Flask
Flask
Actualizado: 20/06/2025

¡Desbloquea el curso de Flask completo!

IA
Ejercicios
Certificado
Entrar

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 Plus

Controladores 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.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

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

⭐⭐⭐⭐⭐
4.9/5 valoración