17

我正在尝试更改列名。第一次尝试是使用这个脚本:

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 脚本中。但是这种额外的重复对我来说有点太多了。任何人都知道这应该怎么做。假设这是一个错误,我想就如何干掉一些解决方法提出建议。

4

3 回答 3

24

这也有效:

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')
于 2017-09-27T16:08:05.777 回答
18

事实证明,有一个比我希望的更 DRY:er 的解决方案。内省!像这样:

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

奇迹般有效!

于 2011-10-06T10:10:11.787 回答
1

我敢打赌它不能生成任何 SQL,因为您的元数据引用被混淆了。您似乎在您的Table类中使用了两个不同的元数据对象,这真的不好。你只需要一个。元数据跟踪对象的陈旧性,是否需要针对对象更新、外键约束等发出查询,并且它需要了解您的所有表和关系。

更改为使用单个MetaData对象,并传递echo=True给您的sqlalchemy.create_engine调用,它将打印它正在使用的 SQL 查询到标准输出。尝试在以相同角色(用户)登录 Postgres 时自己执行该查询。您可能会发现这是一个简单的权限问题。

关于复制粘贴:我认为 Django 有一个很好的约定,即在它们自己的模块中放置Table和声明类并导入它们。但是,因为您必须将MetaData对象传递给Table工厂,所以事情变得复杂了。您可以使用单例/全局元数据对象,或者只是转换为声明性的。

有一段时间,我选择实现单参数函数,该函数返回Table给定元数据的对象并缓存结果——实际上是实现了一个单例模型类。然后我认为这很愚蠢并改用声明式。

于 2011-10-05T15:10:37.163 回答