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
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
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 campo | Tipo de base de datos | Parámetros comunes |
|---|---|---|
| db.Integer | INTEGER | primary_key, autoincrement |
| db.String(N) | VARCHAR(N) | unique, nullable, default |
| db.Text | TEXT | default |
| db.DateTime | DATETIME | default, onupdate |
| db.Boolean | BOOLEAN | default |
| 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
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
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étodo | SQL equivalente | Valor de retorno |
|---|---|---|
| Post.query.all() | SELECT * FROM posts | Lista |
| Post.query.get(1) | WHERE id = 1 | Objeto único o None |
| Post.query.get_or_404(1) | WHERE id = 1 | Objeto único o devuelve 404 automáticamente |
| Post.query.filter_by(category_id=1).all() | WHERE category_id=1 | Lista |
| 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 DESC | Lista |
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