Lo que está pidiendo es una migración de datos , a diferencia de la migración de esquema que es más frecuente en los documentos de Alembic.
Esta respuesta asume que está utilizando declarativo (a diferencia de class-Mapper-Table o core) para definir sus modelos. Debería ser relativamente sencillo adaptar esto a las otras formas.
Tenga en cuenta que Alembic proporciona algunas funciones de datos básicas: op.bulk_insert()
y op.execute()
. Si las operaciones son bastante mínimas, utilícelas. Si la migración requiere relaciones u otras interacciones complejas, prefiero usar todo el poder de los modelos y sesiones como se describe a continuación.
A continuación, se muestra un script de migración de ejemplo que configura algunos modelos declarativos que se utilizarán para manipular datos en una sesión. Los puntos clave son:
Defina los modelos básicos que necesita, con las columnas que necesitará. No necesita todas las columnas, solo la clave principal y las que utilizará.
Dentro de la función de actualización, use op.get_bind()
para obtener la conexión actual y hacer una sesión con ella.
- O use
bind.execute()
para usar el nivel inferior de SQLAlchemy para escribir consultas SQL directamente. Esto es útil para migraciones simples.
Utilice los modelos y la sesión como lo haría normalmente en su aplicación.
"""create teams table
Revision ID: 169ad57156f0
Revises: 29b4c2bfce6d
Create Date: 2014-06-25 09:00:06.784170
"""
revision = '169ad57156f0'
down_revision = '29b4c2bfce6d'
from alembic import op
import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Player(Base):
__tablename__ = 'players'
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String, nullable=False)
team_name = sa.Column('team', sa.String, nullable=False)
team_id = sa.Column(sa.Integer, sa.ForeignKey('teams.id'), nullable=False)
team = orm.relationship('Team', backref='players')
class Team(Base):
__tablename__ = 'teams'
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String, nullable=False, unique=True)
def upgrade():
bind = op.get_bind()
session = orm.Session(bind=bind)
# create the teams table and the players.team_id column
Team.__table__.create(bind)
op.add_column('players', sa.Column('team_id', sa.ForeignKey('teams.id'), nullable=False)
# create teams for each team name
teams = {name: Team(name=name) for name in session.query(Player.team).distinct()}
session.add_all(teams.values())
# set player team based on team name
for player in session.query(Player):
player.team = teams[player.team_name]
session.commit()
# don't need team name now that team relationship is set
op.drop_column('players', 'team')
def downgrade():
bind = op.get_bind()
session = orm.Session(bind=bind)
# re-add the players.team column
op.add_column('players', sa.Column('team', sa.String, nullable=False)
# set players.team based on team relationship
for player in session.query(Player):
player.team_name = player.team.name
session.commit()
op.drop_column('players', 'team_id')
op.drop_table('teams')
La migración define modelos separados porque los modelos en su código representan el estado actual de la base de datos, mientras que las migraciones representan pasos en el camino . Su base de datos puede estar en cualquier estado a lo largo de esa ruta, por lo que es posible que los modelos aún no se sincronicen con la base de datos. A menos que tenga mucho cuidado, usar los modelos reales directamente causará problemas con columnas faltantes, datos no válidos, etc. Es más claro indicar explícitamente exactamente qué columnas y modelos utilizará en la migración.
op.execute
enupgrade()
, ¿hay una manera de proporcionar una plantilla predeterminada para ser utilizado poralembic revision
comandos (un cuerpo predeterminado para la generada.py
archivo)?Recomiendo usar las declaraciones centrales de SQLAlchemy usando una tabla ad-hoc, como se detalla en la documentación oficial , porque permite el uso de SQL agnóstico y escritura pitónica y también es autónomo. SQLAlchemy Core es lo mejor de ambos mundos para los scripts de migración.
A continuación se muestra un ejemplo del concepto:
fuente