Flask-SQLAlchemy — Diseño de modelos de base de datos

En este capítulo aprenderás a definir modelos de datos con Flask-SQLAlchemy, crear tablas de base de datos SQLite e insertar datos de prueba.


¿Por qué usar ORM?

Escribir sentencias SQL directamente para operar la base de datos es tedioso y propenso a errores.

ORM (Mapeo Objeto-Relacional)Te permite definir la estructura de las tablas con clases de Python y operar los datos con métodos de Python.

Flask-SQLAlchemy es la versión integrada de SQLAlchemy para Flask, encapsula operaciones comunes y su configuración es más sencilla.


Instalación y configuración

(venv) $ pip install flask-sqlalchemy

Ejemplo

# Ruta del archivo: app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# Ruta del archivo de base de datos SQLite (ubicado en la raíz del proyecto)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
# Desactivar el seguimiento de modificaciones (ahorra memoria; en versiones futuras estará desactivado por defecto)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Crear la instancia db y vincularla a la app
db = SQLAlchemy(app)

sqlite:///blog.dbLas tres barras indican una ruta relativa. La base de datos SQLite es un archivo; no es necesario instalar ningún software de base de datos, lo que la hace muy adecuada para desarrollo y pruebas.


Definir modelos: Post y Category

Ejemplo

# Ruta del archivo: models.py
from datetime import datetime
from app import db

class Category(db.Model):
    """Categoría de artículo"""
    __tablename__ = 'categories'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(50), unique=True, nullable=False)
    slug = db.Column(db.String(50), unique=True, nullable=False)
    # backref: en el objeto Category se puede obtener de forma inversa todos sus artículos mediante .posts
    posts = db.relationship('Post', backref='category', lazy='dynamic')

    def __repr__(self):
        return f'<Category {self.name}>'


class Post(db.Model):
    """Artículo de blog"""
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    title = db.Column(db.String(200), nullable=False)
    slug = db.Column(db.String(200), unique=True, nullable=False)
    summary = db.Column(db.Text, default='')
    content = db.Column(db.Text, nullable=False)
    # Clave foránea: db.ForeignKey('nombre_de_tabla.nombre_de_campo')
    category_id = db.Column(db.Integer, db.ForeignKey('categories.id'), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    def __repr__(self):
        return f'<Post {self.title}>'

Tipos de campo comunes

Tipo de campoTipo de base de datosParámetros comunes
db.IntegerINTEGERprimary_key, autoincrement
db.String(N)VARCHAR(N)unique, nullable, default
db.TextTEXTdefault
db.DateTimeDATETIMEdefault, onupdate
db.BooleanBOOLEANdefault
db.ForeignKey('tabla.campo')FOREIGN KEY—

Crear tablas de base de datos

A diferencia de migrate en Django, Flask requiere inicializar manualmente las tablas de la base de datos.

(venv) $ flask shell                        # 进入 Flask 交互式 Shell

Ejemplo

# Introducir en flask shell
from app import db
db.create_all()     # Crear las tablas de base de datos correspondientes a todos los modelos
exit()

Después de ejecutarlo, se generará en la raíz del proyectoblog.dbel archivo.

db.create_all()Solo crea las tablas si no existen. Si modificas la estructura del modelo (por ejemplo, añades campos), no actualizará la tabla automáticamente. En producción deberías usar Flask-Migrate (capítulo 5) para gestionar los cambios de estructura.


Insertar datos de prueba con flask shell

Ejemplo

# Introducir en flask shell
from app import db
from models import Category, Post

# 1. Crear la categoría
py_cat = Category(name='Python', slug='python')
css_cat = Category(name='CSS', slug='css')
flask_cat = Category(name='Flask', slug='flask')
db.session.add_all([py_cat, css_cat, flask_cat])
db.session.commit()

# 2. Crear el artículo
post1 = Post(
    title='Guía completa de introducción a Flask',
    slug='flask-beginner-guide',
    summary='Aprende Flask desde cero, cubriendo conceptos clave como rutas, plantillas, ORM, etc.',
    content='<h2>¿Por qué aprender Flask?</h2><p>Flask es el microframework web más flexible de Python...</p>',
    category=flask_cat
)
post2 = Post(
    title='Explicación detallada de las corrutinas en Python',
    slug='python-coroutine',
    summary='Entiende de una vez asyncio, corrutinas y el bucle de eventos.',
    content='<h2>¿Qué es una corrutina?</h2><p>Una corrutina es un esquema de concurrencia más ligero que un hilo...</p>',
    category=py_cat
)
post3 = Post(
    title='Práctica de diseño con CSS Grid',
    slug='css-grid-layout',
    summary='Implementa fácilmente diseños responsivos complejos con CSS Grid.',
    content='<h2>Introducción a Grid</h2><p>Grid es un sistema de diseño bidimensional...</p>',
    category=css_cat
)
db.session.add_all([post1, post2, post3])
db.session.commit()

# 3. Verificar la consulta
print(Post.query.all())
print(Post.query.filter(Post.category_id == 1).all())

Consultas básicas con Flask-SQLAlchemy

MétodoSQL equivalenteValor de retorno
Post.query.all()SELECT * FROM postsLista
Post.query.get(1)WHERE id = 1Objeto único o None
Post.query.get_or_404(1)WHERE id = 1Objeto único o devuelve 404 automáticamente
Post.query.filter_by(category_id=1).all()WHERE category_id=1Lista
Post.query.filter(Post.title.ilike('%flask%')).all()WHERE title LIKE '%flask%'Lista
Post.query.order_by(Post.created_at.desc()).all()ORDER BY created_at DESCLista

Resumen del capítulo

En este capítulo has dominado el flujo completo de Flask-SQLAlchemy: instalar y configurar SQLALCHEMY_DATABASE_URI, definir modelos con db.Model (tipos de campo / claves foráneas / relationship), inicializar las tablas con db.create_all(), e insertar y consultar datos en flask shell.

Hasta aquí, la estructura de datos de los artículos y las categorías ya está establecida en la base de datos SQLite.

Otras extensiones