python-3.x - 是否有一种 python-alembic 方法可以在删除和添加列之间转换数据?

标签 python-3.x sqlite sqlalchemy alembic

我有一个 sqlite3 数据库,使用 python3 中的 SQLAlchemy 访问它。 我想使用数据库迁移工具 alembic 添加一个新列并删除一个旧列。简单示例:

class Model(_Base):
  __tablename__ = 'Model'
  _oid = Column('oid', sa.Integer, primary_key=True)
  _number_int = sa.Column('number_int', sa.Integer)

迁移后应该是这样的:

class Model(_Base):
  __tablename__ = 'Model'
  _oid = Column('oid', sa.Integer, primary_key=True)
  _number_str = sa.Column('number_str', sa.String(length=30))

这里的相关点是 _number_int 中的数据应该像这样转换成 _number_str:

number_conv = {1: 'one', 2: 'two', 3: 'three'}
_number_str = number_conv[_number_int]

是否有一种蒸馏器方法来解决这个问题?这意味着 alembic 本身是否会在其概念/设计中处理此类情况? 我想知道我是否可以为此使用 alembic 工具,或者我是否必须为此编写自己的额外代码。

当然,原始数据转换起来稍微复杂一些。这只是这里的一个例子。

最佳答案

这是蒸馏器 operation reference .有一种方法叫做 bulk_insert()用于批量插入内容,但不用于迁移现有内容。似乎蒸馏器没有内置。但是您可以自己实现数据迁移。

文章 "Migrating content with alembic" 中描述了一种可能的方法.您需要在迁移文件中定义中间表,其中包含两列(number_intnumber_str):

import sqlalchemy as sa

model_helper = sa.Table(
    'Model',
    sa.MetaData(),
    sa.Column('oid', sa.Integer, primary_key=True),
    sa.Column('number_int', sa.Integer),
    sa.Column('number_str', sa.String(length=30)),
)

并使用这个中间表将数据从旧列迁移到新列:

from alembic import op


def upgrade():
    # add the new column first
    op.add_column(
        'Model',
        sa.Column(
            'number_str',
            sa.String(length=30),
            nullable=True
        )
    )

    # build a quick link for the current connection of alembic
    connection = op.get_bind()

    # at this state right now, the old column is not deleted and the
    # new columns are present already. So now is the time to run the
    # content migration. We use the connection to grab all data from
    # the table, convert each number and update the row, which is 
    # identified by its id
    number_conv = {1: 'one', 2: 'two', 3: 'three'}
    for item in connection.execute(model_helper.select()):
        connection.execute(
            model_helper.update().where(
                model_helper.c.id == item.id
            ).values(
                number_str=number_conv[item.number_int]
            )
        )

    # now that all data is migrated we can just drop the old column
    # without having lost any data
    op.drop_column('Model', 'number_int')

这种方法有点嘈杂(您需要手动定义表),但它确实有效。

关于python-3.x - 是否有一种 python-alembic 方法可以在删除和添加列之间转换数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32006683/

相关文章:

python-3.x - SessionNotCreatedException : Message: session not created from disconnected: unable to connect to renderer with ChromeDriver 2. 45 Chrome v71

python - 使用 Python 设置 cx_Oracle 环境变量

java - 如何从android中的特定联系人读取收件箱短信?

SQLite - 如果存在则更新(而不是替换),否则插入

python-2.7 - 是否有可能同时具有一对多和多对多关系的模型?

sqlalchemy - 如何在 SQLAlchemy 中使用二进制数据?

python-3.x - 如何在 Dask 中正确使用 client.scatter

C++智能指针混淆

python - 解析 sqlalchemy 存储过程执行的结果

python - 使用 glob 重复列读取多个文件