❓ Information
- Alembic 사용법 (python data migrations)
❗ Relevant data
🎯 What Is The Objective
Python 에서 사용하는 Database Migration Tool 주로 Alembic + Sqlarchemy로 사용하여 통합 관리하게 됨
📦 Information Resources
🔰 Content ->
1️⃣ Alembic 설치
pip install alembic2️⃣ Alembic의 환경 생성 or 초기화
alembic init 으로 migaration의 환경 생성 migrations 폴더와 alembi.ini 파일도 생성됨
# alembic init {migration의 환경명}
alembic init migrations폴더 설명
- versions - 마이그레이션 할 스크립트 코드가 들어감
- env.py - DB 마이그레이션 시 실행 되는 서버 연결 및 마이그레이션 실행 코드
- script.py.mako - 마이그레이션 템플릿 파일
- alembic.ini - env.py 파일에서 Configuration으로 사용되는 alembic 설정 파일
3️⃣ Alembic database 설정
alembic.ini 파일에 sqlalchemy.url 에 DB 주소를 설정
sqlalchemy.url = postgresql+psycopg2://postgres:postgres@localhost:5432/lmsini파일은 동적으로 sql url을 할당할 수 없기에 class를 만들어 사용하든 python 코드로 사용하든 하면 더 좋다
config = context.config
if not config.get_main_option("sqlalchemy.url"):
config.set_main_option(
"sqlalchemy.url",
"postgresql+psycopg2://{username}:{password}@{host}:{port}/{db_name}".format(
username="postgres",
password="postgres",
host="localhost",
port="5432",
db_name="lms"
)
)4️⃣ alembic 마이그레이션 스크립트 생성
아래 명령어를 사용하면 revision 스크립트가 생기며, revision 버전도 생성된다.
# alembic revision -m "{commit 메시지}"
alembic revision -m "init""""init
Revision ID: 2a1080a73181
Revises:
Create Date: 2024-05-05 11:03:38.853884
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembio.
revision: str = '2a1080a73181'
down_revision: Union[str, Node] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sqeunce[str], None] = None
def upgrade() -> None:
pass
def downgrade() -> None:
passupgrade, downgrade 부분을 수정해주면 되는데 revision 해시값을 이용하며 이 버전으로 upgrade 시에는 upgrade 함수가 downgrade 시에는 downgrade 함수가 호출되어 실행됨.
user, book 테이블을 생성하는 예시:
def upgrade() -> None:
op.create_table(
"user",
sa.Column('id', sa.Integer),
sa.Column('name', sa.String),
sa.PrimaryKeyConstraint('id)
)
op.create_table(
'book',
sa.Column('id', sa.Integer),
sa.Column('title', sa.String),
sa.Column('author', sa.Stirng),
sa.Column('borrowed', sa.String),
sa.PrimaryKeyConstraint('id')
)
def downgrade() -> None:
op.drop_table('user')
op.drop_table('book')5️⃣ Migration 실행
upgrade
upgrade head를 진행하면 db안에 있는 현재 alembic_version의 해시값보다 높은 revision 해시값에 해당하는 스크립트를 실행한다
alembic upgrade head
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> 2a1080a73181, initdowngrade
위에 작성 한 것과 같이 downgrade를 하면 삭제됨
alembic downgrade -1
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.runtime.migration] Running downgrade 2a1080a73181 -> , init6️⃣ revision 코드 자동 생성
alembic은 sqlalchemy와 연동 되어 있다 보니 sqlalchemy에 있는 model을 기반으로 자동으로 revision migration 코드를 생성 해 줄 수 있다. 먼저 아래와 같이 declarative_base를 이용하여 base를 선언한다.
from sqlalchemy.ext.decalrative import declarative_base
Base = declarative_base()Base에 등록된 모델들의 생성이나 변경점을 찾아 자동으로 generate함
from sqlalchemy import Column, Integer, String, Boolean
class test(Base):
__tablename__ = 'test'
id = Column(Integer, primary_key=True)
title = Column(String)
test = Column(String)Target_metadata를 바꿨기 때문에 위에 Base를 기준으로 재설정된다. 그래서 User와 Book은 삭제되고, Test 하나만 남게 되는 revision script 가 완성된다
alembic revision --autogenerate -m "create table test""""create table test
Revision ID: 536d2ba9a373
Revises: 2a1080a73181
Create Date: 2024-05-05 11:39:10.684664
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
revision: str = '536d2ba9a373'
down_revision: Union[str, None] = '2a1080a73181'
branch_labels: Union[str, Sequence[str], None] = None
depneds_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.create_table('test',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('title', sa.String(), nullable=True),
sa.Column('test', sa.String(), nullable=True),
sa.Column('test2', sa.String(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.drop_table('book')
op.drop_table('user')
def downgrade() -> None:
op.create_table('user',
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('name', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('id', name='user_key')
)
op.create_table('book'
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('title', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('author', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('borrowed', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('id', name='book_pkey')
)
op.drop_table('test')여기서 add column 을 한번 해보고 generate 를 다시 해보면 add Column Sctipt 가 생성된걸 알 수 있다.
class test(Base):
__tablename__ = 'test'
id = Column(Integer, primary_key=True)
title = Column(String)
test = Column(String)
test2 = Column(String) # 추가"""add column test2
Revision ID: e3e5f02ba243
Revise: 536d2ba9a373
Create Date: 2024-05-05 11:42:25.873999
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
revision: str = 'e3e5f02ba243'
down_revision: Union[str, None] = '536d2ba9a373'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.add_column('test', sa.Column('test2', sa.String(), nullable=True))
def downgrade() -> None:
op.drop_column('test', 'test2')Alembic history
alembic으로 마이그레이션은 마쳤지만 현재 상태를 확인해 볼 필요성이 있다. 아래와 같이 명령어를 실행하면 현재 어떤 것을 진행했는지 나오게 된다.
alembic histroy --verboseRev: e3e5f02ba243 (head)
Parent: 536d2ba9a373
Path: C:\\dev\\projectName\\migrations\\versions\\2024_05_05_1142-e3e5f02ba243_add_column_test2.py
add column test2
Revision ID: e3e5f02ba243
Revise: 536d2ba9a373
Create Date: 2024-05-05 11:42:25.873999
Rev: 536d2ba9a373
Parent: 2a1080a73181
Path: C:\\dev\\projectName\\migrations\\versions\\2024_05_05_1139-536d2ba9a373_create_table_test.py
create table test
Revision ID: 536d2ba9a373
Revises: 2a1080a73181
Create Date: 2024-05-05 11:39:10.684664
Rev: 2a1080a73181
Parent: <base>
Path: C:\\dev\\projectName\\migrations\\versions\\2024_05_05_1103-2a1080a73181_init.py
init
Revision ID: 2a1080a73181
Revises:
Create Date: 2024-05-05 11:03:38.853884