Flask
Tutorial Flask: Flask-Migrate
Aprende a configurar Flask-Migrate para gestionar migraciones de bases de datos en Flask con SQLAlchemy de forma eficiente y controlada.
Aprende Flask y certifícateConfiguración Flask-Migrate
Flask-Migrate es la extensión estándar que permite gestionar las migraciones de esquema de base de datos en aplicaciones Flask que utilizan SQLAlchemy. Esta herramienta se basa en Alembic, la biblioteca de migraciones de SQLAlchemy, proporcionando una interfaz simplificada a través de comandos de Flask CLI.
Las migraciones son scripts que describen los cambios incrementales en el esquema de la base de datos, permitiendo evolucionar la estructura de datos de forma controlada y reproducible entre diferentes entornos de desarrollo, pruebas y producción.
Instalación de Flask-Migrate
Para comenzar a trabajar con migraciones, necesitas instalar Flask-Migrate en tu entorno virtual:
pip install Flask-Migrate
Esta instalación incluye automáticamente Alembic como dependencia, proporcionando todas las funcionalidades necesarias para la gestión de migraciones.
Configuración inicial en la aplicación
La configuración básica de Flask-Migrate requiere integrar la extensión con tu aplicación Flask y la instancia de SQLAlchemy existente:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://usuario:password@localhost/mi_base_datos'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
migrate = Migrate(app, db)
# Tus modelos existentes
class Usuario(db.Model):
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)
class Producto(db.Model):
id = db.Column(db.Integer, primary_key=True)
nombre = db.Column(db.String(100), nullable=False)
precio = db.Column(db.Decimal(10, 2), nullable=False)
La instancia Migrate requiere dos parámetros: la aplicación Flask y la instancia de SQLAlchemy. Esta configuración establece la conexión entre Flask-Migrate y tu esquema de base de datos definido en los modelos.
Inicialización del repositorio de migraciones
Antes de crear tu primera migración, debes inicializar el repositorio que almacenará todos los archivos de migración:
flask db init
Este comando crea una carpeta migrations/
en tu proyecto con la siguiente estructura:
migrations/
├── alembic.ini
├── env.py
├── script.py.mako
└── versions/
La carpeta versions/ contendrá todos los archivos de migración que generes, mientras que los otros archivos configuran el comportamiento de Alembic para tu proyecto específico.
Configuración avanzada del entorno
El archivo migrations/env.py
contiene la configuración del entorno de migraciones. Flask-Migrate genera automáticamente una configuración funcional, pero puedes personalizarla según tus necesidades:
# migrations/env.py (fragmento relevante)
from alembic import context
from flask import current_app
# Configuración de la base de datos objetivo
config = context.config
config.set_main_option(
'sqlalchemy.url',
str(current_app.extensions['migrate'].db.get_engine().url).replace(
'%', '%%'
)
)
# Configuración de metadatos para auto-generación
target_metadata = current_app.extensions['migrate'].db.metadata
Esta configuración permite que las migraciones detecten automáticamente los cambios en tus modelos SQLAlchemy y generen los scripts de migración correspondientes.
Configuración de opciones específicas
Puedes personalizar el comportamiento de Flask-Migrate mediante opciones adicionales en la inicialización:
from flask_migrate import Migrate
# Configuración con opciones personalizadas
migrate = Migrate(
app,
db,
directory='mi_carpeta_migraciones', # Carpeta personalizada
compare_type=True, # Detectar cambios de tipo
compare_server_default=True # Detectar cambios en valores por defecto
)
La opción compare_type es especialmente útil cuando modificas tipos de columnas, mientras que compare_server_default detecta cambios en valores predeterminados definidos a nivel de base de datos.
Configuración para múltiples bases de datos
Si tu aplicación utiliza múltiples bases de datos, puedes configurar Flask-Migrate para manejar cada una por separado:
# Configuración para múltiples bases de datos
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://localhost/principal'
app.config['SQLALCHEMY_BINDS'] = {
'usuarios': 'mysql://localhost/usuarios_db',
'productos': 'mysql://localhost/productos_db'
}
db = SQLAlchemy(app)
# Configuración separada para cada base de datos
migrate_principal = Migrate(app, db, directory='migrations_principal')
migrate_usuarios = Migrate(app, db, directory='migrations_usuarios')
Esta configuración permite mantener historiales de migración independientes para cada base de datos, facilitando el mantenimiento de esquemas complejos.
Variables de entorno para configuración
Es recomendable utilizar variables de entorno para configurar las conexiones de base de datos en diferentes entornos:
import os
class Config:
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'mysql://localhost/desarrollo'
SQLALCHEMY_TRACK_MODIFICATIONS = False
class ProductionConfig(Config):
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
class DevelopmentConfig(Config):
SQLALCHEMY_DATABASE_URI = 'mysql://localhost/desarrollo'
class TestingConfig(Config):
SQLALCHEMY_DATABASE_URI = 'mysql://localhost/testing'
TESTING = True
# Configuración según el entorno
config = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}
Esta estructura permite que las migraciones se ejecuten correctamente en cualquier entorno sin modificar el código, simplemente cambiando las variables de entorno correspondientes.
Creación y aplicación de migraciones
Una vez configurado Flask-Migrate, el flujo de trabajo con migraciones sigue un patrón consistente: detectar cambios en los modelos, generar scripts de migración y aplicar esos cambios a la base de datos. Este proceso garantiza que la evolución del esquema sea controlada y reproducible.
Generación automática de migraciones
El comando más utilizado para crear migraciones es flask db migrate
, que analiza automáticamente las diferencias entre tus modelos SQLAlchemy actuales y el estado de la base de datos:
flask db migrate -m "Agregar tabla productos"
Este comando genera un archivo de migración en la carpeta migrations/versions/
con un nombre único que incluye un timestamp y el mensaje descriptivo que proporcionaste. El archivo contiene dos funciones principales:
# migrations/versions/001_agregar_tabla_productos.py
def upgrade():
# Cambios para aplicar la migración
op.create_table('producto',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('nombre', sa.String(length=100), nullable=False),
sa.Column('precio', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('fecha_creacion', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
def downgrade():
# Cambios para revertir la migración
op.drop_table('producto')
La función upgrade() contiene las operaciones necesarias para aplicar los cambios, mientras que downgrade() define cómo revertir esos cambios si es necesario.
Aplicación de migraciones
Para aplicar las migraciones pendientes a tu base de datos, utiliza el comando flask db upgrade
:
flask db upgrade
Este comando ejecuta todas las migraciones que no se han aplicado aún, actualizando el esquema de la base de datos al estado más reciente. Flask-Migrate mantiene un registro interno de qué migraciones se han ejecutado para evitar aplicar la misma migración múltiples veces.
Si necesitas aplicar solo hasta una migración específica, puedes indicar su identificador:
flask db upgrade abc123
Revisión y edición de migraciones
Antes de aplicar una migración, es fundamental revisar el contenido del archivo generado. Flask-Migrate hace su mejor esfuerzo para detectar cambios, pero algunas situaciones requieren intervención manual:
# Ejemplo de migración que requiere edición manual
def upgrade():
# Cambio detectado automáticamente
op.add_column('usuario', sa.Column('telefono', sa.String(length=15), nullable=True))
# Operación manual necesaria para poblar datos existentes
connection = op.get_bind()
connection.execute(
"UPDATE usuario SET telefono = '000-000-0000' WHERE telefono IS NULL"
)
# Hacer la columna no nullable después de poblar datos
op.alter_column('usuario', 'telefono', nullable=False)
Esta edición manual es común cuando agregas columnas no nullable a tablas con datos existentes, o cuando necesitas transformar datos durante la migración.
Migraciones para cambios complejos
Algunos cambios en los modelos requieren migraciones más elaboradas. Por ejemplo, cuando renombras una columna:
# Modelo original
class Usuario(db.Model):
id = db.Column(db.Integer, primary_key=True)
nombre_completo = db.Column(db.String(100), nullable=False)
# Modelo modificado
class Usuario(db.Model):
id = db.Column(db.Integer, primary_key=True)
nombre = db.Column(db.String(50), nullable=False)
apellido = db.Column(db.String(50), nullable=False)
La migración generada automáticamente podría eliminar nombre_completo
y crear nombre
y apellido
, perdiendo datos. La versión editada manualmente preserva la información:
def upgrade():
# Agregar nuevas columnas
op.add_column('usuario', sa.Column('nombre', sa.String(length=50), nullable=True))
op.add_column('usuario', sa.Column('apellido', sa.String(length=50), nullable=True))
# Migrar datos existentes
connection = op.get_bind()
result = connection.execute("SELECT id, nombre_completo FROM usuario")
for row in result:
partes = row.nombre_completo.split(' ', 1)
nombre = partes[0]
apellido = partes[1] if len(partes) > 1 else ''
connection.execute(
"UPDATE usuario SET nombre = %s, apellido = %s WHERE id = %s",
(nombre, apellido, row.id)
)
# Hacer las columnas no nullable y eliminar la antigua
op.alter_column('usuario', 'nombre', nullable=False)
op.alter_column('usuario', 'apellido', nullable=False)
op.drop_column('usuario', 'nombre_completo')
Reversión de migraciones
Si necesitas revertir cambios, puedes usar el comando flask db downgrade
:
# Revertir la última migración
flask db downgrade
# Revertir hasta una migración específica
flask db downgrade abc123
# Revertir todas las migraciones
flask db downgrade base
La capacidad de reversión es especialmente valiosa durante el desarrollo cuando necesitas probar diferentes enfoques de esquema, o en producción cuando una migración causa problemas inesperados.
Gestión del historial de migraciones
Para visualizar el estado actual de las migraciones, utiliza:
# Ver el historial de migraciones
flask db history
# Ver la migración actual
flask db current
# Ver migraciones pendientes
flask db show
Estos comandos te permiten monitorear el estado de tu base de datos y planificar las operaciones de migración necesarias.
Migraciones en diferentes entornos
Cuando trabajas con múltiples entornos (desarrollo, pruebas, producción), es crucial mantener sincronizados los esquemas de base de datos:
# En desarrollo - generar migración
flask db migrate -m "Agregar índice email usuario"
# En producción - aplicar migración
export FLASK_ENV=production
export DATABASE_URL=mysql://prod_user:password@prod_server/prod_db
flask db upgrade
Las migraciones garantizan que todos los entornos tengan exactamente el mismo esquema, eliminando inconsistencias que podrían causar errores en producción.
Resolución de conflictos de migración
Cuando múltiples desarrolladores crean migraciones simultáneamente, pueden surgir conflictos de ramificación. Flask-Migrate proporciona herramientas para resolverlos:
# Detectar ramas múltiples en el historial
flask db branches
# Crear una migración de fusión
flask db merge -m "Fusionar ramas de migración" abc123 def456
La migración de fusión combina múltiples líneas de desarrollo en una sola, manteniendo la integridad del historial de cambios del esquema.
Otras lecciones de Flask
Accede a todas las lecciones de Flask y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Flask
Introducción Y Entorno
Instalación Y Configuración Flask Con Venv
Introducción Y Entorno
Rutas Endpoints Rest Get
Api Rest
Respuestas Con Esquemas Flask Marshmallow
Api Rest
Rutas Endpoints Rest Post, Put Y Delete
Api Rest
Manejo De Errores Y Códigos De Estado Http
Api Rest
Ejercicios de programación de Flask
Evalúa tus conocimientos de esta lección Flask-Migrate con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.