Migración de base de datos con Alembic

En este capítulo aprenderás a usar Alembic para gestionar cambios en la estructura de la base de datos, y a comprender las similitudes y diferencias con Django Migration y Flask-Migrate.


¿Por qué necesitas una herramienta de migración?

Base.metadata.create_all()También tiene un defecto fatal: solo crea tablas cuando no existen; las modificaciones de la estructura de tablas existentes no se sincronizan automáticamente.

AlembicEs la herramienta oficial de migración de SQLAlchemy; la de Djangomakemigrations/migratey Flask-Migrate de Flask, en su núcleo están inspirados en el diseño de Alembic.


Instalación e inicialización

(venv) $ pip install alembic
(venv) $ alembic init alembic
Creating directory alembic/... done

Estructura de directorios generada:

alembic/
├── versions/          # 迁移脚本存放目录
├── env.py             # 迁移环境配置(需手动修改!)
└── script.py.mako     # 迁移脚本模板
alembic.ini            # Alembic 配置文件

Configura env.py para conectarlo a tus modelos

Este es un paso clave: Alembic, por defecto, no sabe dónde están tus modelos SQLAlchemy.

Ejemplo

# Ruta del archivo: alembic/env.py (modifica las partes clave)
import sys
from pathlib import Path

# Agrega el directorio raíz del proyecto a sys.path (garantiza que puedas importar tus propios módulos)
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from database import Base, engine
from models import Category, Post   # Importa todos los modelos para asegurar que Base.metadata los contenga

# target_metadata debe establecerse en los metadatos del modelo
target_metadata = Base.metadata

Al mismo tiempo, modificaalembic.inila conexión de base de datos en:

# 文件路径:alembic.ini
sqlalchemy.url = sqlite:///./blog.db

Los tres pasos de la migración

PasoComandoFunciónEquivalente en Django
Inicializaciónalembic init alembicCrear el entorno de migración (solo una vez)—
Generaralembic revision --autogenerate -m "descripción"Detecta cambios en los modelos y genera el script de migraciónmakemigrations
Ejecutaralembic upgrade headEjecuta todas las migraciones no aplicadasmigrate

Generar y ejecutar migraciones

(venv) $ alembic revision --autogenerate -m "初始化 Post 和 Category 模型"
INFO  [alembic.autogenerate] Detected added table 'categories'
INFO  [alembic.autogenerate] Detected added table 'posts'
Generating alembic/versions/xxxx_initial.py ... done

(venv) $ alembic upgrade head
INFO  [alembic.runtime.migration] Running upgrade -> xxxx, 初始化

Práctica: agregar el campo read_count

Ejemplo

# Ruta del archivo: agregar en la clase Post de models.py
class Post(Base):
    # ... campos existentes ...
    read_count = Column(Integer, default=0)   # Número de lecturas
(venv) $ alembic revision --autogenerate -m "Post 新增 read_count 字段"
(venv) $ alembic upgrade head

Reversión

(venv) $ alembic downgrade -1        # 回退到上一个版本

alembic upgrade headenheadrepresenta la última versión. También puedes especificar un número de versión concreto:alembic upgrade xxxx(ID de versión).


Comparación de herramientas de migración de los tres frameworks

OperaciónDjangoFlask(Flask-Migrate)FastAPI(Alembic)
InicializaciónNo requiereflask db initalembic init alembic
Generar migraciónmakemigrationsflask db migrate -m "descripción"alembic revision --autogenerate -m "descripción"
Ejecutar migraciónmigrateflask db upgradealembic upgrade head
Reversiónmigrate app 0001flask db downgradealembic downgrade -1
Grado de automatizaciónMáximoMedioRequiere configurar manualmente env.py

Resumen del capítulo

En este capítulo dominaste el flujo completo de Alembic: `alembic init` para inicializar, configurar `env.py` para conectar los modelos, `revision --autogenerate` para generar migraciones, `upgrade head` para ejecutarlas y `downgrade` para revertirlas.

Alembic requiere más pasos de configuración que las herramientas de migración de Django/Flask, pero es de más bajo nivel y más flexible.

Avance del próximo capítulo: cuando haya muchos artículos, se necesitarán búsqueda y paginación. En el próximo capítulo se implementarán la búsqueda combinada por palabras clave y la paginación basada en offset/limit.

Otras extensiones