[解決済み] Alembicアップグレードスクリプトでインサートやアップデートを実行するにはどうすればよいですか?
質問
Alembicのアップグレード時にデータを変更する必要があります。
私は現在、最初のリビジョンで 'players' テーブルを持っています。
def upgrade():
op.create_table('player',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.Unicode(length=200), nullable=False),
sa.Column('position', sa.Unicode(length=200), nullable=True),
sa.Column('team', sa.Unicode(length=100), nullable=True)
sa.PrimaryKeyConstraint('id')
)
teams' テーブルを導入したい。 2回目のリビジョンを作成しました。
def upgrade():
op.create_table('teams',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=80), nullable=False)
)
op.add_column('players', sa.Column('team_id', sa.Integer(), nullable=False))
2回目のマイグレーションでは、以下のデータも追加してほしいです。
-
チーム テーブルにデータを入力します。
INSERT INTO teams (name) SELECT DISTINCT team FROM players;
-
players.team名に基づきplayers.team_idを更新します。
UPDATE players AS p JOIN teams AS t SET p.team_id = t.id WHERE p.team = t.name;
アップグレードスクリプト内で挿入や更新を実行するにはどうすればよいですか?
どのように解決するのですか?
あなたが求めているのは データの移行 とは対照的に スキーママイグレーション というのは、Alembic のドキュメントで最も一般的なものです。
この回答は、モデルを定義するためにdeclarative(class-Mapper-Tableやcoreとは対照的)を使用していることを前提としています。 これを他の形式に適応させるのは比較的簡単なはずです。
Alembicはいくつかの基本的なデータ関数を提供していることに注意してください。
op.bulk_insert()
と
op.execute()
. もし操作がかなり最小限のものであれば、それらを使用します。 移行にリレーションシップやその他の複雑な相互作用が必要な場合は、以下で説明するように、モデルとセッションのフルパワーを使用することをお勧めします。
以下は、セッションでデータを操作するために使用されるいくつかの宣言的なモデルを設定するマイグレーションスクリプトの例です。 キーポイントは
-
必要なカラムを含む、基本的なモデルを定義します。 すべてのカラムが必要なわけではなく、主キーと使用するカラムだけでよい。
-
アップグレード機能内では
op.get_bind()
を使用して現在の接続を取得し、その接続でセッションを作成します。-
または
bind.execute()
を使えば、SQLAlchemy の下位レベルを使って、SQL クエリを直接書けます。これは単純なマイグレーションに便利です。
-
または
-
アプリケーションで通常行うように、モデルとセッションを使用します。
"""create teams table
Revision ID: 169ad57156f0
Revises: 29b4c2bfce6d
Create Date: 2014-06-25 09:00:06.784170
"""
revision = '169ad57156f0'
down_revision = '29b4c2bfce6d'
from alembic import op
import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Player(Base):
__tablename__ = 'players'
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String, nullable=False)
team_name = sa.Column('team', sa.String, nullable=False)
team_id = sa.Column(sa.Integer, sa.ForeignKey('teams.id'), nullable=False)
team = orm.relationship('Team', backref='players')
class Team(Base):
__tablename__ = 'teams'
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String, nullable=False, unique=True)
def upgrade():
bind = op.get_bind()
session = orm.Session(bind=bind)
# create the teams table and the players.team_id column
Team.__table__.create(bind)
op.add_column('players', sa.Column('team_id', sa.ForeignKey('teams.id'), nullable=False)
# create teams for each team name
teams = {name: Team(name=name) for name in session.query(Player.team).distinct()}
session.add_all(teams.values())
# set player team based on team name
for player in session.query(Player):
player.team = teams[player.team_name]
session.commit()
# don't need team name now that team relationship is set
op.drop_column('players', 'team')
def downgrade():
bind = op.get_bind()
session = orm.Session(bind=bind)
# re-add the players.team column
op.add_column('players', sa.Column('team', sa.String, nullable=False)
# set players.team based on team relationship
for player in session.query(Player):
player.team_name = player.team.name
session.commit()
op.drop_column('players', 'team_id')
op.drop_table('teams')
マイグレーションで別々のモデルを定義しているのは、コード中のモデルが 現在の状態 を表し、マイグレーションは 途中のステップ . データベースはその途中のどの状態であってもよいので、モデルはまだデータベースと同期していないかもしれません。よほど注意しない限り、実際のモデルを直接使用すると、カラムがない、データが無効であるなどの問題が発生します。マイグレーションで使用するカラムとモデルを正確に明示する方が明確です。
関連
-
[解決済み] 関数デコレータを作成し、それらを連鎖させるには?
-
[解決済み] プログラムの実行やシステムコマンドの呼び出しはどのように行うのですか?
-
[解決済み] 割り当て後にリストが予期せず変更されました。その理由と防止策を教えてください。
-
[解決済み] pipでPythonの全パッケージをアップグレードする方法
-
[解決済み] どうすれば、文字列中のリテラルな中抜き文字を印刷し、また.formatを使用することができるのでしょうか?
-
[解決済み] Pythonスクリプトのプロファイリングはどのように行うのですか?
-
[解決済み] スクリプトを実行しているPythonのバージョンを確認するにはどうしたらいいですか?
-
[解決済み] スクリプトを終了させるには?
-
[解決済み] 異なる順序で同じ要素を持つ2つのJSONオブジェクトを等しく比較するには?
-
[解決済み] pipの依存性/必要条件をリストアップする方法はありますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] PythonでファイルのMD5チェックサムを計算するには?重複
-
[解決済み] Pythonです。未束縛のメソッドを束縛する?
-
[解決済み] Pythonのキャッシュライブラリはありますか?
-
[解決済み] 文字列から先頭と末尾のスペースを削除するには?
-
[解決済み] Ctrl-CでPythonスクリプトを終了できない
-
[解決済み] Pythonによる一対のクロスプロダクト [重複] (英語)
-
[解決済み] Pandasを使って、既存のExcelファイルに新しいシートを保存する方法は?
-
[解決済み] Pythonの文字列書式をリストで使う
-
[解決済み] Django filter queryset __in for *every* item in list
-
[解決済み] 新しいpip backtrackingの実行時問題の解決