Alembic 업그레이드 중에 데이터를 변경해야합니다.
현재 첫 번째 개정판에 ‘플레이어’테이블이 있습니다.
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')
)
‘팀’테이블을 소개하고 싶습니다. 두 번째 개정판을 만들었습니다.
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))
두 번째 마이그레이션에서 다음 데이터도 추가하고 싶습니다.
-
팀 테이블 채우기 :
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 문서에서 가장 널리 퍼진 스키마 마이그레이션 과 반대로 데이터 마이그레이션 입니다.
이 답변은 모델을 정의하기 위해 선언적 (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')
코드의 모델 은 데이터베이스 의 현재 상태 를 나타내고 마이그레이션은 그 과정의 단계를 나타내 므로 마이그레이션은 별도의 모델을 정의합니다 . 데이터베이스는 해당 경로를 따라 어떤 상태에있을 수 있으므로 모델이 아직 데이터베이스와 동기화되지 않을 수 있습니다. 매우주의하지 않는 한 실제 모델을 직접 사용하면 누락 된 열, 유효하지 않은 데이터 등의 문제가 발생합니다. 마이그레이션에 사용할 열과 모델을 정확히 명시하는 것이 더 명확합니다.
답변
다음 예제와 같이 직접 SQL을 사용할 수도 있습니다 ( Alembic Operation Reference ) 참조 :
from alembic import op
# revision identifiers, used by Alembic.
revision = '1ce7873ac4ced2'
down_revision = '1cea0ac4ced2'
branch_labels = None
depends_on = None
def upgrade():
# ### commands made by andrew ###
op.execute('UPDATE STOCK SET IN_STOCK = -1 WHERE IN_STOCK IS NULL')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
답변
공식 문서에 자세히 설명 된대로 임시 테이블을 사용하는 SQLAlchemy 핵심 문을 사용하는 것이 좋습니다 . 왜냐하면 불가지론적인 SQL 및 파이썬 쓰기를 사용할 수 있고 자체 포함되기 때문입니다. SQLAlchemy Core는 마이그레이션 스크립트를위한 두 가지 장점 중 최고입니다.
다음은 개념의 예입니다.
from sqlalchemy.sql import table, column
from sqlalchemy import String
from alembic import op
account = table('account',
column('name', String)
)
op.execute(
account.update().\\
where(account.c.name==op.inline_literal('account 1')).\\
values({'name':op.inline_literal('account 2')})
)
# If insert is required
from sqlalchemy.sql import insert
from sqlalchemy import orm
session = orm.Session(bind=bind)
bind = op.get_bind()
data = {
"name": "John",
}
ret = session.execute(insert(account).values(data))
# for use in other insert calls
account_id = ret.lastrowid