Saltar a contenido

🗄️ Migraciones de Base de Datos con Alembic

Alembic es una herramienta de migraciones de base de datos ligera para SQLAlchemy. Permite gestionar los cambios en el esquema de la base de datos de forma incremental y controlada, asegurando que la estructura de la base de datos esté siempre sincronizada con los modelos de la aplicación. En el P2P Dashboard, Alembic es fundamental para la evolución del esquema de PostgreSQL.

¿Por qué usar Alembic?

  • Control de Versiones: Permite versionar los cambios en el esquema de la base de datos, al igual que se versiona el código fuente.
  • Despliegue Consistente: Asegura que todos los entornos (desarrollo, staging, producción) tengan la misma versión del esquema de la base de datos.
  • Colaboración: Facilita el trabajo en equipo, ya que los desarrolladores pueden aplicar y revertir migraciones de forma segura.
  • Evita Pérdida de Datos: Permite realizar cambios en el esquema sin perder los datos existentes.

Configuración de Alembic

El archivo de configuración principal de Alembic es alembic.ini, ubicado en la raíz del proyecto. Este archivo define la ubicación de los scripts de migración, la conexión a la base de datos y otras opciones.

# alembic.ini
[alembic]
script_location = alembic
sqlalchemy.url = postgresql://user:password@localhost:5432/p2p_db # ¡Importante! Esto debe ser configurado dinámicamente en producción

# ... otras configuraciones ...

Nota Importante: En un entorno de producción, la sqlalchemy.url no debe estar codificada directamente en alembic.ini. En su lugar, env.py (dentro del directorio alembic/) se encarga de cargar la URL de la base de datos desde las variables de entorno, asegurando que las credenciales no se expongan y que la configuración sea flexible para diferentes entornos.

Directorio de Migraciones (alembic/versions/)

Todos los scripts de migración generados por Alembic se almacenan en el directorio alembic/versions/. Cada archivo representa una migración específica y contiene dos funciones principales:

  • upgrade(): Define los cambios a aplicar para actualizar el esquema de la base de datos a una nueva versión.
  • downgrade(): Define los cambios para revertir el esquema a la versión anterior.

Comandos Comunes de Alembic

1. Inicializar Alembic (Una sola vez)

Si Alembic no ha sido inicializado en el proyecto, se hace con:

alembic init alembic

Esto crea el directorio alembic/ y el archivo alembic.ini.

2. Generar una Nueva Migración

Cuando realizas cambios en tus modelos de SQLAlchemy (ej. añades una nueva tabla, modificas una columna), debes generar una nueva migración. Alembic puede autodetectar muchos de estos cambios.

alembic revision --autogenerate -m "Descripción de la migración"

Esto creará un nuevo archivo Python en alembic/versions/ con las funciones upgrade() y downgrade() pre-rellenadas con los cambios detectados. Siempre revisa y ajusta este archivo manualmente para asegurar que los cambios son correctos y para añadir cualquier lógica personalizada (ej. migración de datos).

3. Aplicar Migraciones

Para aplicar todas las migraciones pendientes y actualizar la base de datos a la última versión, usa:

alembic upgrade head

Para aplicar una migración específica (por su ID) o un número determinado de migraciones:

alembic upgrade <revision_id>
alembic upgrade +1 # Aplica la siguiente migración

4. Revertir Migraciones

Para revertir la última migración aplicada:

alembic downgrade -1

Para revertir a una versión específica:

alembic downgrade <revision_id>

Para revertir todas las migraciones (base de datos vacía):

alembic downgrade base

5. Mostrar el Estado de las Migraciones

Para ver qué migraciones se han aplicado y cuáles están pendientes:

alembic history
alembic current

Ejemplo de un Script de Migración

Un script de migración típico en alembic/versions/ se vería así:

"""
Descripción de la migración

Revision ID: 04722e5b11a9
Revises: 
Create Date: 2023-01-01 10:00:00.000000

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '04722e5b11a9'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table(
        'users',
        sa.Column('id', sa.UUID(), nullable=False),
        sa.Column('username', sa.String(), nullable=False),
        sa.Column('hashed_password', sa.String(), nullable=False),
        sa.Column('is_active', sa.Boolean(), nullable=True),
        sa.Column('is_admin', sa.Boolean(), nullable=True),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('username')
    )
    # ### end Alembic commands ###


def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table('users')
    # ### end Alembic commands ###

El uso de Alembic es una práctica esencial para mantener la base de datos del P2P Dashboard en un estado consistente y gestionable a lo largo del tiempo.