Was Sie verlangen, ist eine Datenmigration im Gegensatz zur Schemamigration , die in den Alembic-Dokumenten am häufigsten verwendet wird.
Bei dieser Antwort wird davon ausgegangen, dass Sie deklarativ (im Gegensatz zu Class-Mapper-Table oder Core) verwenden, um Ihre Modelle zu definieren. Es sollte relativ einfach sein, dies an die anderen Formen anzupassen.
Beachten Sie, dass Alembic einige grundlegende Datenfunktionen bietet: op.bulk_insert()
undop.execute()
. Wenn die Operationen ziemlich minimal sind, verwenden Sie diese. Wenn die Migration Beziehungen oder andere komplexe Interaktionen erfordert, bevorzuge ich die Nutzung der vollen Leistung von Modellen und Sitzungen, wie unten beschrieben.
Im Folgenden finden Sie ein Beispiel für ein Migrationsskript, mit dem einige deklarative Modelle eingerichtet werden, mit denen Daten in einer Sitzung bearbeitet werden. Die wichtigsten Punkte sind:
Definieren Sie die Grundmodelle, die Sie benötigen, mit den Spalten, die Sie benötigen. Sie benötigen nicht jede Spalte, nur den Primärschlüssel und die von Ihnen verwendeten.
Verwenden Sie op.get_bind()
in der Upgrade-Funktion, um die aktuelle Verbindung abzurufen und eine Sitzung damit zu erstellen.
- Oder verwenden Sie
bind.execute()
, um die untere Ebene von SQLAlchemy zu verwenden, um SQL-Abfragen direkt zu schreiben. Dies ist nützlich für einfache Migrationen.
Verwenden Sie die Modelle und die Sitzung wie gewohnt in Ihrer Anwendung.
"""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')
Die Migration definiert separate Modelle, da die Modelle in Ihrem Code den aktuellen Status der Datenbank darstellen, während die Migrationen Schritte auf dem Weg darstellen . Ihre Datenbank befindet sich möglicherweise in einem beliebigen Zustand auf diesem Pfad, sodass die Modelle möglicherweise noch nicht mit der Datenbank synchronisiert sind. Wenn Sie nicht sehr vorsichtig sind, führt die direkte Verwendung der realen Modelle zu Problemen mit fehlenden Spalten, ungültigen Daten usw. Es ist klarer, genau anzugeben, welche Spalten und Modelle Sie bei der Migration verwenden werden.
op.execute
in übergeben wollteupgrade()
, gibt es eine Möglichkeit, eine Standardvorlage bereitzustellen, die vomalembic revision
Befehl verwendet werden kann (ein Standardtext für die generierte.py
Datei)?