Как выполнить вставки и обновления в сценарии обновления перегонного куба?
мне нужно изменить данные во время обновления перегонного куба.
в настоящее время у меня есть таблица "игроки" в первой редакции:
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')
)
Я хочу представить таблицу "команд". Я создал вторую редакцию:
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))
Я хотел бы, чтобы вторая миграция также добавила следующие данные:
-
заполнить таблицу команд:
INSERT INTO teams (name) SELECT DISTINCT team FROM players;
-
игроки обновления.team_id на основе игроков.команда имя:
UPDATE players AS p JOIN teams AS t SET p.team_id = t.id WHERE p.team = t.name;
Как выполнить вставки и обновления внутри сценария обновления?
1 ответ:
то, что вы просите-это миграция данных, а не схема миграции это наиболее распространено в документах перегонного куба.
этот ответ предполагает, что вы используете декларативный (в отличие от class-Mapper-Table или core) для определения ваших моделей. Это должно быть относительно просто адаптировать это к другим формам.
обратите внимание, что перегонный куб обеспечивает некоторые основные функции данных:
op.bulk_insert()
иop.execute()
. Если операции достаточно минимальны, используйте их. Если миграция требует отношений или других сложных взаимодействий, я предпочитаю использовать всю мощь моделей и сеансов, как описано ниже.ниже приведен пример сценария миграции, который устанавливает некоторые декларативные модели, которые будут использоваться для управления данными в сеансе. Ключевыми моментами являются:
- определите основные модели, которые вам нужны, со столбцами, которые вам понадобятся. Вы не нужно каждый столбец, только первичный ключ и те, которые вы будете использовать.
в функции обновления используйте
op.get_bind()
получить текущее соединение, и сделать сеанс с ним.
- или использовать
bind.execute()
чтобы использовать нижний уровень SQLAlchemy для прямой записи SQL-запросов. Это полезно для простых миграций.используйте модели и сессии, как обычно в вашем приложение.
"""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')
миграция определяет отдельные модели, потому что модели в коде представления состояние базы данных, в то время как миграции представляют шаги по пути. Ваша база данных может находиться в любом состоянии по этому пути, поэтому модели могут еще не синхронизироваться с базой данных. Если вы не будете очень осторожны, использование реальных моделей напрямую вызовет проблемы с отсутствующими столбцами, недопустимыми данных и т. д. Яснее явно указать, какие именно столбцы и модели вы будете использовать в миграции.