我正在尝试更改列名。首次尝试使用此脚本:
meta = MetaData()
users = Table('users', meta,
Column('id', Integer, primary_key=True),
Column('name', String(50), unique=True),
Column('email', String(120), unique=True)
)
def upgrade(migrate_engine):
meta.bind = migrate_engine
users.c.id.alter(name='id')
def downgrade(migrate_engine):
meta.bind = migrate_engine
users.c.id.alter(name='user_id')
在我的开发数据库(sqlite)上运行migrate.py test
,升级和降级也是如此。但是当它在Heroku(使用PostgreSQL 8.3)上部署到我的测试环境时,我会在尝试升级时得到一个跟踪。要点是这个消息:
sqlalchemy.exc.ProgrammingError: (ProgrammingError) column "id" does not exist
然后我尝试在升级方法中使用users.c.user_id
。这在两种环境中都失败了。:
AttributeError: user_id
我现在使用的解决方法是这个脚本:
meta_old = MetaData()
meta_new = MetaData()
users_old = Table('users', meta_old,
Column('user_id', Integer, primary_key=True),
Column('name', String(50), unique=True),
Column('email', String(120), unique=True)
)
users_new = Table('users', meta_new,
Column('id', Integer, primary_key=True),
Column('name', String(50), unique=True),
Column('email', String(120), unique=True)
)
def upgrade(migrate_engine):
meta_old.bind = migrate_engine
users_old.c.user_id.alter(name='id')
def downgrade(migrate_engine):
meta_new.bind = migrate_engine
users_new.c.id.alter(name='user_id')
已经建议将模型复制粘贴到sqlalchemy-migrate脚本。但是这个额外的重复对我来说有点太多了。任何人都知道应该怎么做。假设这是一个错误,我想了解如何干预解决方法。
答案 0 :(得分:13)
事实证明,这是一个比我希望的更干的解决方案。内省!像这样:
def upgrade(migrate_engine):
meta = MetaData(bind=migrate_engine)
users = Table('users', meta, autoload=True)
users.c.user_id.alter(name='id')
def downgrade(migrate_engine):
meta = MetaData(bind=migrate_engine)
users = Table('users', meta, autoload=True)
users.c.id.alter(name='user_id')
像魅力一样!
答案 1 :(得分:8)
这个也有效:
from alembic import op
....
def upgrade(migrate_engine):
op.alter_column('users', 'user_id', new_column_name='id')
def downgrade(migrate_engine):
op.alter_column('users', 'id', new_column_name='user_id')
答案 2 :(得分:1)
我敢打赌,它无法生成任何SQL,因为您的元数据引用混淆了。您似乎在Table
类中使用了两个不同的元数据对象,这确实不太好。你只需要一个。元数据跟踪对象的陈旧性,是否需要发出对象更新查询,外键约束等,并且需要知道所有表和关系。
更改为使用单个MetaData
对象,并将echo=True
传递给sqlalchemy.create_engine
调用,它将打印出它正在使用的SQL查询到标准输出。在以Postgres的相同角色(用户)身份登录时尝试自己执行该查询。您可能会发现这是一个简单的权限问题。
关于复制粘贴:我认为Django有一个很好的约定,即在自己的模块中放置Table
和声明性类并导入它们。但是,因为您必须将MetaData
对象传递给Table
工厂,这会使问题复杂化。您可以使用单例/全局元数据对象,也可以只转换为声明性。
有一段时间我选择实现一个参数函数,它返回给定元数据的Table
个对象并缓存结果 - 实际上是实现单例模型类。然后我觉得这很愚蠢,转而陈述。