当我添加新列并从预先存在的列迁移数据时,会添加该列,但不会迁移数据(只保留列中的空值)。
from alembic import op # NOQA
import sqlalchemy as sa # NOQA
from pycoin.encoding import a2b_hashed_base58 # NOQA
from binascii import hexlify # NOQA
from datetime import datetime, timedelta # NOQA
from sqlalchemy.ext.declarative import declarative_base # NOQA
Base = declarative_base()
Session = sa.orm.sessionmaker()
class Farmer(Base):
__tablename__ = 'farmer'
id = sa.Column(sa.Integer, primary_key=True)
btc_addr = sa.Column(sa.String(35), unique=True) # TODO migrate to nodeid
def upgrade():
bind = op.get_bind()
session = Session(bind=bind)
op.add_column('farmer', sa.Column('nodeid', sa.String(length=40),
nullable=True))
for farmer in session.query(Farmer):
nodeid = hexlify(a2b_hashed_base58(farmer.btc_addr)[1:])
if isinstance(nodeid, bytes):
nodeid = nodeid.decode("utf-8")
farmer.nodeid = nodeid
print("saved nodeid: {0}".format(nodeid)) # called
session.commit()
编辑:
这个问题已得到正确回答,我创建了一个isolated example here来演示如何进行数据迁移,因为我无法在任何地方找到一个好的。
答案 0 :(得分:0)
作为一般规则,在迁移脚本中使用ORM是一个坏主意。正如您已经经历过的那样,您必须做一些奇怪的事情以避免错误。很明显,你已经看到了这一点,因此决定在脚本本身中包含你的模型的副本。
您的解决方案存在的问题是,您复制的Farmer
模型没有要迁移到的nodeid
属性。如果您在迁移脚本中包含的模型副本中包含此属性,我认为您将能够执行数据迁移。
但无论如何,我认为在迁移中明确复制的模型可能会导致错误。我的建议是您不要使用ORM来迁移数据。如果在SQLAlchemy中使用较低级别的SQL生成支持,您仍然可以拥有非常体面的东西。您将创建一个临时Table
实例,该实例表示数据库表在需要迁移的确切位置的状态,然后您可以在SQLAlchemy中发出SQL类以进行所需的更改。
有关包含数据迁移的示例迁移脚本结构,请参阅官方Alembic文档中的此示例:http://alembic.readthedocs.org/en/latest/cookbook.html#conditional-migration-elements。
有关实现与您类似的数据迁移脚本的示例,请参阅https://julo.ch/blog/migrating-content-with-alembic/。