当前位置: 首页 > 面试题库 >

如何在Alembic升级脚本中执行插入和更新?

锺离高丽
2023-03-14
问题内容

我需要在Alembic升级期间更改数据。

我目前在第一个修订版中有一个“玩家”表:

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))

我希望第二次迁移也添加以下数据:

  1. 填充团队表:

    INSERT INTO teams (name) SELECT DISTINCT team FROM players;
    
  2. 根据players.team名称更新players.team_id:

    UPDATE players AS p JOIN teams AS t SET p.team_id = t.id WHERE p.team = t.name;
    

如何在升级脚本中执行插入和更新?


问题答案:

您需要的是 数据迁移 ,而不是Alembic文档中最普遍的 模式迁移

该答案假设您使用声明式(而不是class-Mapper-Table或core)定义模型。使它适应其他形式应该相对简单。

请注意,Alembic提供了一些基本的数据功能:op.bulk_insert()op.execute()。如果操作很少,请使用这些操作。如果迁移需要关系或其他复杂的交互,我更喜欢使用模型和会话的全部功能,如下所述。

以下是示例迁移脚本,该脚本设置了一些声明性模型,这些模型将用于处理会话中的数据。关键点是:

  1. 使用所需的列定义所需的基本模型。您不需要每一列,只需要主键和将要使用的列。

  2. 在升级功能中,用于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')
    

迁移定义了单独的模型,因为代码中的模型表示数据库的 当前状态 ,而迁移表示 过程中的步骤
。您的数据库可能沿着该路径处于任何状态,因此模型可能尚未与数据库同步。除非您非常小心,否则直接使用真实模型会导致缺少列,无效数据等问题。更清楚地明确指出要在迁移中使用的列和模型。



 类似资料:
  • 问题内容: 我有一个简单的脚本blah.py(使用Python 2): 如果我通过以下方式执行脚本: 它输出参数,但是如果我通过以下方式执行脚本: 发生错误: 因此参数不会传递给脚本。 PATH中的python.exe。路径中也包含blah.py的文件夹。 python.exe是执行* .py文件的默认程序。 问题是什么? 问题答案: 执行脚本而不在前面键入“ python”时,你需要了解有关Wi

  • 问题内容: 我保留一个名为的shell脚本文件 ,并从构建中执行该文件。 当我执行构建时,它失败。 控制台输出如下: 我在应该保留外壳脚本文件以便执行的位置上感到困惑。 问题答案: 如果看到错误消息,则提示 在工作空间中构建/ var / lib / jenkins / workspace / AutoScript 并根据您的评论将urltest.sh放入 / var / lib / jenkin

  • 问题内容: 我有一些要自动执行的SQL脚本。过去,我使用过SQL * Plus,并从bash脚本中手动调用了sqlplus二进制文件。 但是,我试图找出是否有一种方法可以连接到数据库,并从bash脚本内部调用该脚本……以便我可以插入查询并使查询相对于特定天数运行过去。 问题答案: 我有点困惑。您应该能够从bash脚本中调用sqlplus。这可能就是您在第一个陈述中所做的 尝试在bash脚本中执行以

  • Azure DocumentDB 不支持更新测试。是否有合理的解决方法来实现相同的功能? 使用检查文档是否存在的存储过程来确定是否应该执行插入或更新是一种有效的策略吗? 如果我需要批量执行数千个这些操作,该怎么办? 在这里投票支持该功能: http://feedback.azure.com/forums/263030-documentdb/suggestions/7075256-provide-f

  • 问题内容: 我有一个带有数据库转储的SQL脚本。如何使用Hibernate执行它? 我这样尝试过: 但是它仅在包含单个SQL查询且我需要运行多个插入和其他复杂内容时才有效。 RDBMS:Oracle数据库11g快捷版11.2.0.2.0版-64位生产 问题答案: 用开始结束块包装查询。喜欢

  • 我们使用的是Liquibase 3.6.3版本 我们正在使用SQL服务器数据库上的liquibase运行SQL升级脚本,使用liquibase.bat(我们作为安装的一部分获得),如下所示。这是按预期工作的。 命令: liquibase.bat--ChangeLogFile=...\MasterChangelog.xml--驱动程序==com.microsoft.sqlserver.jdbc.SQ