Flask: MVC

Aprende a implementar el patrón MVC (Modelo-Vista-Controlador) en Flask, organiza controladores y aprovecha la potencia de Jinja para generar vistas dinámicas. Mejora la mantenibilidad y la claridad de tu proyecto web en Python.

Aprende Flask GRATIS y certifícate

En el desarrollo de aplicaciones web con Flask, la adopción de un patrón MVC (Modelo-Vista-Controlador) brinda una estructura limpia y ordenada, facilitando la separación de responsabilidades. Con el microframework Flask, y la integración de Jinja como motor de plantillas, se obtienen vistas dinámicas y flexibles para la capa de presentación.

Qué es el patrón MVC

El patrón MVC consiste en dividir la aplicación en tres componentes principales:

  1. Modelo (Model): Gestiona la lógica de la aplicación relacionada con los datos, usualmente enlazado con la base de datos.
  2. Vista (View): Se encarga de la representación visual de la información, habitualmente mediante plantillas.
  3. Controlador (Controller): Actúa como intermediario, recibiendo las peticiones del usuario y orquestando la interacción entre el modelo y la vista.

En Flask, los modelos suelen desarrollarse con librerías como SQLAlchemy, las vistas se construyen con Jinja y los controladores se establecen a través de funciones que manejan las rutas.

Organización en Flask

Una estructura recomendable para proyectos de tamaño medio o grande en Flask podría ser la siguiente:

mi_proyecto/
├── app.py
├── config.py
├── models/
│   └── usuario.py
├── controllers/
│   └── usuario_controller.py
├── templates/
│   └── usuario/
│       └── detalle.html
│       └── lista.html
├── static/
│   └── css/
│   └── js/
└── requirements.txt
  • app.py: Contiene la aplicación Flask y la configuración inicial.
  • models/: Aloja las entidades que representan las tablas de la base de datos.
  • controllers/: Contiene los archivos que gestionan la lógica de cada recurso o entidad.
  • templates/: Carpeta para las vistas de Jinja, separadas por secciones.
  • static/: Para archivos estáticos como CSS, JavaScript o imágenes.

Definición de modelos

En la carpeta models, se puede ubicar una clase que represente, por ejemplo, un usuario en la base de datos:

# models/usuario.py
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Usuario(db.Model):
    __tablename__ = 'usuarios'

    id = db.Column(db.Integer, primary_key=True)
    nombre = db.Column(db.String(50), nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

    def __repr__(self):
        return f'<Usuario {self.nombre}>'

Este archivo define el modelo que interactúa con la base de datos, aportando la columna id como clave primaria, así como nombre y email para los datos del usuario.

Controladores y rutas

En Flask, cada ruta se asocia a una función (u objeto) que orquesta la lógica principal. En el patrón MVC, esas funciones representan el controlador. Un ejemplo de controlador para usuarios:

# controllers/usuario_controller.py
from flask import Blueprint, render_template, request, redirect, url_for
from models.usuario import Usuario, db

usuario_bp = Blueprint('usuario_bp', __name__)

@usuario_bp.route('/usuarios', methods=['GET'])
def lista_usuarios():
    usuarios = Usuario.query.all()
    return render_template('usuario/lista.html', usuarios=usuarios)

@usuario_bp.route('/usuarios/<int:usuario_id>', methods=['GET'])
def detalle_usuario(usuario_id):
    usuario = Usuario.query.get_or_404(usuario_id)
    return render_template('usuario/detalle.html', usuario=usuario)

@usuario_bp.route('/usuarios/crear', methods=['POST'])
def crear_usuario():
    nombre = request.form.get('nombre')
    email = request.form.get('email')
    nuevo_usuario = Usuario(nombre=nombre, email=email)
    db.session.add(nuevo_usuario)
    db.session.commit()
    return redirect(url_for('usuario_bp.lista_usuarios'))

Aquí se ilustran tres rutas:

  1. lista_usuarios: Devuelve la lista completa de usuarios consultando el modelo.
  2. detalle_usuario: Muestra la información de un usuario en particular.
  3. crear_usuario: Procesa un formulario enviado por método POST, crea un registro en la base de datos y redirige a la lista.

Para usar este controlador, se registra en app.py (o en un archivo principal), de la siguiente manera:

from flask import Flask
from controllers.usuario_controller import usuario_bp
from models.usuario import db

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mi_base.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db.init_app(app)
app.register_blueprint(usuario_bp)

with app.app_context():
    db.create_all()

if __name__ == '__main__':
    app.run(debug=True)

Uso de plantillas Jinja

La capa de vista en el patrón MVC de Flask se maneja mediante Jinja. Este motor de plantillas lee archivos HTML y permite incluir variables y estructuras de control. Un ejemplo en templates/usuario/lista.html:

<!DOCTYPE html>
<html>
<head>
    <title>Lista de usuarios</title>
</head>
<body>
    <h1>Lista de usuarios</h1>
    <ul>
        {% for usuario in usuarios %}
            <li>
                <a href="{{ url_for('usuario_bp.detalle_usuario', usuario_id=usuario.id) }}">
                    {{ usuario.nombre }} ({{ usuario.email }})
                </a>
            </li>
        {% endfor %}
    </ul>
</body>
</html>

La variable usuarios, pasada desde el controlador, se itera con la sintaxis {% for ... in ... %} y se muestra el nombre y el correo.

Otra plantilla para templates/usuario/detalle.html podría:

<!DOCTYPE html>
<html>
<head>
    <title>Detalle del usuario</title>
</head>
<body>
    <h1>Detalle de {{ usuario.nombre }}</h1>
    <p>Correo: {{ usuario.email }}</p>
    <a href="{{ url_for('usuario_bp.lista_usuarios') }}">Volver a la lista</a>
</body>
</html>

Mediante Jinja, se mezcla lógica mínima de presentación con variables y enlaces que devuelven información dinámica al usuario.

Formularios y envío de datos

Para crear un nuevo usuario, se puede ofrecer un formulario en una plantilla:

<form action="{{ url_for('usuario_bp.crear_usuario') }}" method="POST">
    <label for="nombre">Nombre</label>
    <input type="text" name="nombre" id="nombre" required>
    <label for="email">Email</label>
    <input type="email" name="email" id="email" required>
    <button type="submit">Crear</button>
</form>

Al enviarse, la ruta usuario_bp.crear_usuario gestiona los datos y los inserta en la base de datos. Esta arquitectura en Flask separa claramente la vista (HTML) del controlador (lógica de inserción).

Buenas prácticas en el patrón MVC

  • Separar la lógica de negocio (modelos) de la lógica de control (rutas).
  • Ubicar archivos HTML en templates/, agrupados por sección para mantener orden.
  • Emplear Blueprints para dividir el proyecto en múltiples controladores, cada uno enfocado en un recurso o módulo distinto.
  • Reutilizar partes de la vista con la herencia de plantillas de Jinja, a través de archivos base y bloques que se extienden en subplantillas.
  • Definir funciones claras y pequeñas en los controladores, facilitando la lectura y la testabilidad del código.

Extensión con un sistema de archivos estáticos

El directorio static/ se utiliza para hospedar archivos CSS, JavaScript o imágenes. En Flask, se accede a estos recursos a través de la ruta /static. Por ejemplo, si se ubica un archivo styles.css dentro de static/css/, se puede enlazar en una plantilla:

<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">

Esta organización ofrece coherencia entre los módulos, los assets y las plantillas del proyecto.

Al llevar el patrón MVC a tu aplicación de Flask, se favorece la escalabilidad, la legibilidad y la coherencia de todo el proyecto. Separar el código en modelos, controladores y vistas no solo mejora el mantenimiento, sino que también agiliza el crecimiento y la incorporación de nuevas funcionalidades en la aplicación. Con la potencia de Jinja como motor de plantillas, la creación de interfaces dinámicas se adapta con naturalidad a las necesidades de cada proyecto web en Python.

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.