IF0100 - Programación OO II

Unidad 4: Manejo de Persistencia

Clase 5: Alembic - Migraciones

Martes, 19 de mayo de 2026 Semana 16 - Martes (120 minutos) 60 min Teoría 60 min Práctica

E6: Proyecto Final - Jueves 28/05/2026 (9 días)

Objetivos de Aprendizaje

Al finalizar esta clase, serás capaz de:

  • Entender qué son las migraciones de base de datos
  • Configurar Alembic en un proyecto de Python
  • Crear migraciones automáticas y manuales
  • Aplicar y revertir migraciones de esquema
  • Manejar cambios de base de datos en entornos de producción

Que es Alembic? (10 min)

Alembic es una herramienta de migracion para SQLAlchemy. Permite:

  • Versionar cambios en el esquema de base de datos
  • Aplicar cambios de forma controlada
  • Revertir cambios si algo falla
  • Mantener sincronizados modelos y base de datos
Cuando usar migraciones:
  • Agregar/eliminar tablas
  • Agregar/eliminar columnas
  • Cambiar tipos de datos
  • Crear indices

Configuracion (15 min)

Instalacion

pip install alembic

Inicializar Alembic

# En la raiz del proyecto
alembic init alembic

Configurar alembic.ini

# alembic.ini
[alembic]
script_location = alembic
prepend_sys_path = .
version_path_separator = os

sqlalchemy.url = sqlite:///./taskflow.db

Configurar env.py

# alembic/env.py
from logging.config import fileConfig
from sqlalchemy import engine_from_config, pool
from alembic import context
import sys
import os

# Agregar el path del proyecto
sys.path.insert(0, os.getcwd())

# Importar modelos
from database import Base
from models.usuario import Usuario
from models.proyecto import Proyecto
from models.tarea import Tarea
from models.comentario import Comentario

config = context.config
fileConfig(config.config_file_name)
target_metadata = Base.metadata

Crear Migraciones (20 min)

Migracion Automatica

# Detectar cambios automaticamente
alembic revision --autogenerate -m "Crear tablas iniciales"

Migracion Manual

# Crear migracion vacia
alembic revision -m "Agregar columna avatar a usuarios"

Contenido de una migracion

# alembic/versions/xxxx_agregar_avatar.py
from alembic import op
import sqlalchemy as sa

def upgrade():
    # Agregar columna
    op.add_column('usuarios', 
        sa.Column('avatar', sa.String(255), nullable=True)
    )

def downgrade():
    # Eliminar columna
    op.drop_column('usuarios', 'avatar')

Operaciones comunes

def upgrade():
    # Crear tabla
    op.create_table(
        'notificaciones',
        sa.Column('id', sa.Integer(), primary_key=True),
        sa.Column('mensaje', sa.String(200), nullable=False),
        sa.Column('leida', sa.Boolean(), default=False),
        sa.Column('usuario_id', sa.Integer(), sa.ForeignKey('usuarios.id'))
    )
    
    # Agregar columna
    op.add_column('tareas', sa.Column('prioridad', sa.String(20), default='media'))
    
    # Crear indice
    op.create_index('ix_tareas_prioridad', 'tareas', ['prioridad'])
    
    # Modificar columna
    op.alter_column('usuarios', 'email', nullable=False)

def downgrade():
    op.drop_index('ix_tareas_prioridad', 'tareas')
    op.drop_column('tareas', 'prioridad')
    op.drop_table('notificaciones')

Aplicar Migraciones (10 min)

# Aplicar todas las migraciones pendientes
alembic upgrade head

# Aplicar una migracion especifica
alembic upgrade +1

# Revertir ultima migracion
alembic downgrade -1

# Revertir todo
alembic downgrade base

# Ver historial
alembic history

# Ver version actual
alembic current
Importante: Siempre revisa el SQL generado antes de aplicar en produccion.

Ejercicio: Agregar Tabla Etiquetas (20 min)

Crear migracion para agregar sistema de etiquetas a las tareas:

# 1. Crear modelo Etiqueta
# models/etiqueta.py
from sqlalchemy import String, Table, Column, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from typing import List

# Tabla de asociacion (muchos a muchos)
tarea_etiqueta = Table(
    'tarea_etiqueta',
    Base.metadata,
    Column('tarea_id', ForeignKey('tareas.id'), primary_key=True),
    Column('etiqueta_id', ForeignKey('etiquetas.id'), primary_key=True)
)

class Etiqueta(Base):
    __tablename__ = "etiquetas"
    
    id: Mapped[int] = mapped_column(primary_key=True)
    nombre: Mapped[str] = mapped_column(String(50), unique=True)
    color: Mapped[str] = mapped_column(String(7), default="#3498db")  # Hex
    
    # Relacion muchos a muchos
    tareas: Mapped[List["Tarea"]] = relationship(
        secondary=tarea_etiqueta,
        back_populates="etiquetas"
    )

# 2. Actualizar Tarea
class Tarea(Base):
    # ... columnas existentes ...
    etiquetas: Mapped[List["Etiqueta"]] = relationship(
        secondary=tarea_etiqueta,
        back_populates="tareas"
    )

# 3. Crear migracion
# alembic revision --autogenerate -m "Agregar tabla etiquetas"

# 4. Aplicar migracion
# alembic upgrade head
E5 Proyecto: Implementa el sistema de etiquetas y migra la base de datos.

Resumen

  • Alembic: Sistema de migraciones para SQLAlchemy
  • upgrade(): Aplicar cambios
  • downgrade(): Revertir cambios
  • revision --autogenerate: Crear migracion automatica
  • upgrade head: Aplicar todas las migraciones
  • downgrade -1: Revertir ultima migracion
← Anterior: CRUD SQLAlchemy
Clase 20 de 25
Siguiente: Repository Pattern →