python - que - ¿Cómo ejecuto inserciones y actualizaciones en un script de actualización de Alembic?
pip3 no se reconoce como un comando interno o externo (1)
Necesito alterar los datos durante una actualización de Alembic.
Actualmente tengo una mesa de ''jugadores'' en una primera revisión:
def upgrade():
op.create_table(''player'',
sa.Column(''id'', sa.Integer(), nullable=False),
sa.Column(''name'', sa.Unicode(length=200), nullable=False),
sa.Column(''position'', sa.Unicode(length=200), nullable=True),
sa.Column(''team'', sa.Unicode(length=100), nullable=True)
sa.PrimaryKeyConstraint(''id'')
)
Quiero introducir una mesa de ''equipos''. He creado una segunda revisión:
def upgrade():
op.create_table(''teams'',
sa.Column(''id'', sa.Integer(), nullable=False),
sa.Column(''name'', sa.String(length=80), nullable=False)
)
op.add_column(''players'', sa.Column(''team_id'', sa.Integer(), nullable=False))
Me gustaría que la segunda migración también agregue los siguientes datos:
Tabla de equipos de población:
INSERT INTO teams (name) SELECT DISTINCT team FROM players;
Actualice players.team_id basado en players.team name:
UPDATE players AS p JOIN teams AS t SET p.team_id = t.id WHERE p.team = t.name;
¿Cómo ejecuto inserciones y actualizaciones dentro del script de actualización?
Lo que solicita es una migración de datos , a diferencia de la migración de esquemas que prevalece en los documentos de Alembic.
Esta respuesta asume que está utilizando declarativo (en lugar 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 básicas de datos: op.bulk_insert()
y op.execute()
. Si las operaciones son mínimas, úsalas. 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.
El siguiente es un ejemplo de script de migración que configura algunos modelos declarativos que se utilizarán para manipular los datos en una sesión. Los puntos clave son:
- Defina los modelos básicos que necesita, con las columnas que necesitará. No necesita cada columna, solo la clave principal y las que usará.
Dentro de la función de actualización, use
op.get_bind()
para obtener la conexión actual, y haga 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.
- O use
Use 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 podría estar en cualquier estado a lo largo de esa ruta, por lo que los modelos podrían no estar sincronizados con la base de datos todavía. A menos que tenga mucho cuidado, el uso directo de modelos reales causará problemas con columnas faltantes, datos no válidos, etc. Es más claro que se establezca explícitamente qué columnas y modelos utilizará en la migración.