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

migrate.py test私の開発データベース(sqlite)での実行は機能し、アップグレードとダウングレードも機能します。しかし、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 スクリプトに貼り付けることは、既に推奨されている方法です。しかし、この余分な重複は私には少し多すぎます。これをどのように行うべきかは誰でも知っています。バグだと仮定して、回避策をいくつか DRY する方法について提案をお願いします。

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

これには、私が望んでいたよりもさらにドライなソリューションがあることがわかりました。内省!そのようです:

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 を生成できないに違いありません。クラスで2 つの異なるメタデータ オブジェクトを使用しているようですがTable、それは本当に良くありません。必要なのは 1 つだけです。メタデータは、オブジェクトの更新、外部キー制約などのクエリを発行する必要があるかどうか、およびすべてのテーブルと関係について知る必要があるかどうかにかかわらず、オブジェクトの古さを追跡します。

単一のMetaDataオブジェクトを使用するように変更しecho=Truesqlalchemy.create_engine呼び出しに渡すと、使用している SQL クエリが標準出力に出力されます。Postgres に同じロール (ユーザー) としてログインしている間に、そのクエリを自分で実行してみてください。単純なアクセス許可の問題であることがわかる場合があります。

Tableコピーと貼り付けについて: Django には、宣言型のクラスを独自のモジュールに配置してインポートするという良い規則があると思います。ただし、ファクトリにMetaDataオブジェクトを渡す必要があるためTable、問題が複雑になります。シングルトン/グローバル メタデータ オブジェクトを使用することも、単に宣言型に変換することもできます。

しばらくの間Table、メタデータを指定してオブジェクトを返し、結果をキャッシュする、引数が 1 つの関数を実装することにしました。つまり、シングルトン モデル クラスを実装していました。それから私はそれがばかげていると判断し、宣言型に切り替えました。

于 2011-10-05T15:10:37.163 に答える