我有一个sqlite3
数据库,在SQLAlchemy
中使用python3
访问它。
我想添加一个新的,并使用数据库结合工具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本身在其概念/设计中处理类似的情况? 我想知道如果我可以使用alembic工具,或者我必须自己做额外的代码。
当然原始数据转换起来有点复杂。这只是一个例子。
答案 0 :(得分:3)
这是alembic operation reference。有一种名为bulk_insert()
的方法用于批量插入内容,但没有用于迁移现有内容的方法。似乎alembic并没有内置它。但您可以自己实现数据迁移。
文章"Migrating content with alembic"中描述了一种可能的方法。您需要在迁移文件中定义中间表,其中包含两列(number_int
和number_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')
这种方法有点吵(你需要手动定义表),但它可以工作。