Alembic 공식 문서
SQLAlchemy + Alembic 조합을 이용한 마이그레이션 가이드
Python 의 마이그레이션 툴인 Alembic 사용법
데이터베이스 마이그레이션 도구 Alembic
SQLAlchemy
를 사용하고 있을 때 데이터베이스를 관리해주는 마이그레이션 도구Tip! 추가 내용
migration
테이블이 존재$ pip install alembic
alembic
명령어 사용 가능$ alembic init {migration의 환경명}
alembic.ini
파일과 {migration의 환경명}
디렉토리가 생성됨{migration의 환경명}
새로운 폴더를 생성하여 만들어줌alembic.ini
env.py
파일에서 Configuration 파일로 사용되는 alembic
설정 파일env.py
script.py.mako
versions
env.py
와 versions
두 가지env.py
파일로 한 번 환경을 세팅하고 그 이후로는 versions
를 이용하여 관리alembic.ini
파일을 열고 sqlalchemy.url
변수에 연결하고자 하는 데이터베이스 주소를 입력# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8
sqlalchemy.url = mysql+pymysql://root:pwd@mysql:3306/hwaya
string
관련 함수를 사용할 수 없으며 오직 정적 문자열만을 이용해야 함alembic.ini
파일에 있는 sqlalchemy.url
변수를 제거한 후 env.py
파일에서 sqlalchemy.url
을 수동으로 설정할 수 있는 방법 존재# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
if not config.get_main_option("sqlalchemy.url"):
config.set_main_option(
"sqlalchemy.url",
"mysql+pymysql://{username}:{password}@{host}:{port}/{db_name}".format(
username="root",
password="pwd",
host="mysql",
port="3306",
db_name="hwaya"
)
)
env.py
파일에은 Python 코드이기 때문에 Python 에서 제공하는 함수 등을 이용하여 환경별로 데이터베이스 마이그레이션을 쉽게할 수 있음alembic
에서 마이그레이션 스크립트 템플릿을 자동으로 만들어주는 명령어를 사용하여 초기 파일 생성$ alembic revision -m "{commit 메세지}"
revision
명령어에 m 옵션을 사용하여 해당 마이그레이션에 대한 코멘트 가능revision
∙ down_revision
이라는 변수가 보임alembic
은 마이그레이션 스크립트가 동작되었는지를 확인# Script 예시
"""{commit 메세지}
Revision ID: e19af14ddb13
Revises:
Create Date: 2023-01-10 22:10:21.507160
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'e19af14ddb13'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
pass
def downgrade():
pass
upgrade
함수에는 이 마이그레이션을 적용했을 때 사용할 스크립트가 들어감alembic upgrade
명령어와 함께 revision_hash
를 입력하면 해당 해쉬에 맞는 마이그레이션 스크립트의 upgrade
함수를 순차적으로 호출하여 마이그레이션이 진행$ alembic upgrade {revision_hash}
downgrade
함수에는 마이그레이션 이후 이를 다시 롤백할 경우 발생하는데 구체적으로는 아래와 같이 동작downgrade
는 현재의 revision
에서 +- 숫자를 조정 입력하여 롤백과 업그레이드를 반복할 수 있음$ alembic downgrade {revision_hash or current_revision +- 1}
# Script 예시
"""{commit 메세지}
Revision ID: e19af14ddb13
Revises:
Create Date: 2023-01-10 22:10:21.507160
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'e19af14ddb13'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
op.create_table("memos",
sa.Column('id', sa.String(length=200), nullable=False),
sa.Column('title', sa.String(length=100), nullable=False, index=True),
sa.Column('content', sa.Text, nullable=True),
sa.Column('is_favorite', sa.Boolean(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
def downgrade():
op.drop_table("memos")
alembic
의 op
에서 제공하는 create_table
∙ drop_table
등의 함수를 사용하여 시작 쿼리를 정의하고 SQLAlchemy
의 Column
∙ String
등을 사용하여 컬럼의 정보를 정의할 수 있음alembic upgrade
의 head
를 이용하면 최신의 마이그레이션 스크립트까지 전부 적용$ alembic upgrade head
Tip! 추가 내용
$ alembic upgrade head
upgrade
의 커맨드로 마이그레이션을 실행head
는 최신 버전까지의 마이그레이션을 실행한다는 의미head
가 아닌 +1
을 사용$ alembic downgrade base
downgrade
커맨드를 사용base
가 아닌 -1
을 사용alembic
에서 제공하는 autogenerate
옵션은 SQLAlchemy
의 ORM 을 이용하여 정의한 Model 의 메타데이터를 읽어 변경된 부분을 자동으로 확인하여 마이그레이션 스크립트를 작성해줌autogenerate
를 꾸준히 사용해야 하며 애플리케이션 개발 중간에 사용하는 경우 변경점을 alembic
을 파악하지 못하여 오히려 좋지 않은 결과를 초래하기도 함from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
# add your model's MetaData object here
# for 'autogenerate' support
target_metadata = Base.metadata
autogenerate
옵션을 사용하기 위해서는 먼저 target_metadata
변수를 설정SQLAlchemy
를 사용하고 있다면 제공하는 declarative_base
함수에서 반환하는 metadata
를 사용할 수 있음alembic_version
이라는 이름의 테이블이 하나 더 생성됨alembic
의 버전 관리 테이블을 다른 스키마에서 운영하는 방법alembic downgrade
를 진행한 뒤 env.py
파일에서 스키마를 지정하여 alembic
의 테이블을 별도로 관리 가능def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
include_schema=True,
version_table_schema="alembic"
)
connection.execute(
"CREATE SCHEMA IF NOT EXISTS {schema}".format(schema="alembic")
)
with context.begin_transaction():
context.run_migrations()
alembic
이라는 이름으로 스키마 설정alembic
스키마가 없을 경우 자동으로 만들어 줄 수 있도록 쿼리를 삽입