您要求的是数据迁移,而不是Alembic 文档中最流行的模式迁移。
此答案假设您使用声明性(而不是类映射器表或核心)来定义您的模型。将其适应其他形式应该相对简单。
请注意,Alembic 提供了一些基本的数据函数: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')
迁移定义了单独的模型,因为代码中的模型代表数据库的当前状态,而迁移代表沿途的步骤。您的数据库可能处于该路径上的任何状态,因此模型可能尚未与数据库同步。除非您非常小心,否则直接使用真实模型会导致缺少列、无效数据等问题。明确说明您将在迁移中使用哪些列和模型会更清楚。