Flask: MVC

Descubre cómo implementar el patrón MVC en Flask para crear aplicaciones web escalables y mantenibles con modelos, vistas y controladores.

Aprende Flask GRATIS y certifícate

Arquitectura MVC en Flask

El patrón Model-View-Controller (MVC) representa uno de los paradigmas arquitectónicos más utilizados en el desarrollo web moderno. En Flask, aunque el framework no impone una estructura MVC estricta por defecto, implementar este patrón resulta fundamental para crear aplicaciones escalables y mantenibles.

Fundamentos del patrón MVC

La arquitectura MVC divide una aplicación en tres componentes interconectados, cada uno con responsabilidades específicas y bien definidas. Esta separación permite que los desarrolladores trabajen en diferentes aspectos de la aplicación sin interferir entre sí.

El Modelo gestiona los datos y la lógica de negocio de la aplicación. En Flask, esto incluye la definición de estructuras de datos, validaciones, operaciones de base de datos y reglas de negocio. Los modelos actúan como la fuente única de verdad para los datos de la aplicación.

La Vista se encarga de la presentación de los datos al usuario. En el contexto de Flask, las vistas son típicamente plantillas HTML que reciben datos del controlador y los presentan de forma estructurada y atractiva.

El Controlador actúa como intermediario entre el modelo y la vista. Procesa las peticiones del usuario, interactúa con los modelos para obtener o modificar datos, y selecciona la vista apropiada para mostrar la respuesta.

Implementación de modelos en Flask

Los modelos en Flask se implementan comúnmente utilizando SQLAlchemy, que proporciona un ORM robusto para la gestión de datos. Un modelo típico define la estructura de una tabla de base de datos y encapsula la lógica relacionada con esa entidad.

from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

db = SQLAlchemy()

class Usuario(db.Model):
    __tablename__ = 'usuarios'
    
    id = db.Column(db.Integer, primary_key=True)
    nombre = db.Column(db.String(80), nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    fecha_registro = db.Column(db.DateTime, default=datetime.utcnow)
    
    def __repr__(self):
        return f'<Usuario {self.nombre}>'
    
    def to_dict(self):
        return {
            'id': self.id,
            'nombre': self.nombre,
            'email': self.email,
            'fecha_registro': self.fecha_registro.isoformat()
        }

Los modelos también pueden incluir métodos de clase para operaciones comunes como búsquedas o validaciones específicas:

class Usuario(db.Model):
    # ... campos anteriores ...
    
    @classmethod
    def buscar_por_email(cls, email):
        return cls.query.filter_by(email=email).first()
    
    def validar_email(self):
        import re
        patron = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        return re.match(patron, self.email) is not None

Controladores y rutas en Flask

Los controladores en Flask se implementan mediante funciones de vista que manejan las rutas HTTP. Estas funciones procesan las peticiones, interactúan con los modelos y devuelven respuestas apropiadas.

from flask import Blueprint, render_template, request, redirect, url_for, flash

usuarios_bp = Blueprint('usuarios', __name__, url_prefix='/usuarios')

@usuarios_bp.route('/')
def listar_usuarios():
    usuarios = Usuario.query.all()
    return render_template('usuarios/lista.html', usuarios=usuarios)

@usuarios_bp.route('/crear', methods=['GET', 'POST'])
def crear_usuario():
    if request.method == 'POST':
        nombre = request.form.get('nombre')
        email = request.form.get('email')
        
        # Validación básica
        if not nombre or not email:
            flash('Todos los campos son obligatorios', 'error')
            return render_template('usuarios/crear.html')
        
        # Crear nuevo usuario
        usuario = Usuario(nombre=nombre, email=email)
        
        if not usuario.validar_email():
            flash('Email no válido', 'error')
            return render_template('usuarios/crear.html')
        
        db.session.add(usuario)
        db.session.commit()
        
        flash('Usuario creado exitosamente', 'success')
        return redirect(url_for('usuarios.listar_usuarios'))
    
    return render_template('usuarios/crear.html')

La organización en Blueprints permite estructurar los controladores de forma modular, agrupando rutas relacionadas y facilitando el mantenimiento del código.

Vistas y plantillas

Las vistas en Flask utilizan el motor de plantillas Jinja2 para generar contenido HTML dinámico. Las plantillas reciben datos del controlador y los presentan de forma estructurada.

<!-- templates/usuarios/lista.html -->
{% extends "base.html" %}

{% block title %}Lista de Usuarios{% endblock %}

{% block content %}
<div class="container">
    <h1>Usuarios Registrados</h1>
    
    <a href="{{ url_for('usuarios.crear_usuario') }}" class="btn btn-primary">
        Nuevo Usuario
    </a>
    
    <div class="usuarios-grid">
        {% for usuario in usuarios %}
        <div class="usuario-card">
            <h3>{{ usuario.nombre }}</h3>
            <p>{{ usuario.email }}</p>
            <small>Registrado: {{ usuario.fecha_registro.strftime('%d/%m/%Y') }}</small>
        </div>
        {% endfor %}
    </div>
</div>
{% endblock %}

Las plantillas pueden incluir lógica condicional y bucles para presentar datos de forma dinámica:

<!-- templates/usuarios/crear.html -->
{% extends "base.html" %}

{% block content %}
<div class="form-container">
    <h2>Crear Nuevo Usuario</h2>
    
    {% with messages = get_flashed_messages(with_categories=true) %}
        {% if messages %}
            {% for category, message in messages %}
                <div class="alert alert-{{ category }}">{{ message }}</div>
            {% endfor %}
        {% endif %}
    {% endwith %}
    
    <form method="POST">
        <div class="form-group">
            <label for="nombre">Nombre:</label>
            <input type="text" id="nombre" name="nombre" required>
        </div>
        
        <div class="form-group">
            <label for="email">Email:</label>
            <input type="email" id="email" name="email" required>
        </div>
        
        <button type="submit">Crear Usuario</button>
    </form>
</div>
{% endblock %}

Estructura de directorios MVC

Una aplicación Flask bien estructurada siguiendo el patrón MVC organiza los archivos de forma lógica y escalable:

mi_aplicacion/
├── app/
│   ├── __init__.py
│   ├── models/
│   │   ├── __init__.py
│   │   ├── usuario.py
│   │   └── producto.py
│   ├── controllers/
│   │   ├── __init__.py
│   │   ├── usuarios.py
│   │   └── productos.py
│   ├── templates/
│   │   ├── base.html
│   │   ├── usuarios/
│   │   │   ├── lista.html
│   │   │   └── crear.html
│   │   └── productos/
│   │       ├── lista.html
│   │       └── detalle.html
│   └── static/
│       ├── css/
│       ├── js/
│       └── img/
├── config.py
└── run.py

Integración de componentes MVC

La integración efectiva de los componentes MVC requiere una comunicación clara entre las capas. Los controladores actúan como orquestadores, coordinando las operaciones entre modelos y vistas:

@usuarios_bp.route('/<int:usuario_id>')
def detalle_usuario(usuario_id):
    # El controlador solicita datos al modelo
    usuario = Usuario.query.get_or_404(usuario_id)
    
    # Puede realizar operaciones adicionales
    estadisticas = {
        'total_pedidos': usuario.pedidos.count(),
        'ultimo_acceso': usuario.ultimo_acceso
    }
    
    # Pasa los datos a la vista
    return render_template('usuarios/detalle.html', 
                         usuario=usuario, 
                         estadisticas=estadisticas)

Esta separación de responsabilidades facilita el testing, el mantenimiento y la escalabilidad de la aplicación, permitiendo modificar cada componente de forma independiente sin afectar a los demás.

Empezar curso de Flask

Lecciones de este módulo de Flask

Lecciones de programación del módulo MVC del curso de Flask.

Ejercicios de programación en este módulo de Flask

Evalúa tus conocimientos en MVC con ejercicios de programación MVC de tipo Test, Puzzle, Código y Proyecto con VSCode.