BackEnd King KY

TIL43 - alembic에서 metadata를 왜 설정해야 할까 본문

Database

TIL43 - alembic에서 metadata를 왜 설정해야 할까

Django King, Lee 2023. 2. 4. 18:40
728x90

alembic에서 metadata를 왜 설정해야 할까


티스토리로 보기 불편하신 경우, Github를 통해 보실 수 있습니다.

출처는 alembic 1.9.2 공식문서 입니다.

Intro

현재 회사에서 FastAPI를 이용하다 보니 sqlalchemy를 이용하고 있습니다.

Django의 경우, 굳이 마이그레이션 툴을 설치하지 않아도 Django 하나만 있으면 할 수 있는데 sqlalchemy는 alembic이란 라이브러리를 이용합니다.

alembic 설정 같은 건 이미 많이 나와있으니, 제가 겪은 상황에 대해 포스팅하려고 합니다.


Django 마이그레이션과 alembic

Django에선 python manage.py makemigrations를 입력하면 데이터베이스에 반영해주기 위한 마이그레이션 파일을 만들어줍니다.

파일을 보면 테이블 생성/수정/삭제 등에 대해 CreateModel, AlterModel과 같이 코드가 작성되어 있습니다.

즉, 사용자가 모델 정의만 해놓으면 자동으로 생성해주는 스크립트를 만들어준다는 의미입니다.

이 기능은 alembic도 해줄 수 있습니다.


autogenerate

alembic에서 python manage.py makemigrations와 같은 기능을 하는 일반적인 명령어는. alembic revision -m "text" 입니다.

이렇게 되면 text에 적힌 내용을 제목으로 해서 마이그레이션 파일이 생성됩니다.

예를 들어, textcreate_new_tables라고 입력하면 해당 내용이 반영되는 것입니다.

image
"""create new tables

Revision ID: f7e46a04bc17
Revises: 42eaaa081d83
Create Date: 2023-02-04 16:34:10.948079

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'f7e46a04bc17'
down_revision = '42eaaa081d83'
branch_labels = None
depends_on = None


def upgrade() -> None:
    pass


def downgrade() -> None:
    pass

그런데, 마이그레이션 파일을 보면 Django처럼 스크립트를 만들어준다고 했는데 아무것도 적혀있지 않습니다.

이럴 때 사용하는 명령어가 --autogenerate 입니다.

alembic revision --autogenerate -m "text"

해당 옵션은 모델에 정의된 메타데이터를 읽어 변경된 부분을 자동으로 확인하여 스크립트로 반영해줍니다.

"""drop all table : town, city

Revision ID: 22c0d6aa967e
Revises: f7e46a04bc17
Create Date: 2023-02-04 16:48:26.353902

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = '22c0d6aa967e'
down_revision = 'f7e46a04bc17'
branch_labels = None
depends_on = None


def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table('town')
    op.drop_table('city')
    # ### end Alembic commands ###


def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('city',
    sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('city_id_seq'::regclass)"), autoincrement=True, nullable=False),
    sa.Column('created_at', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=False),
    sa.Column('name', sa.VARCHAR(length=10), autoincrement=False, nullable=False),
    sa.PrimaryKeyConstraint('id', name='city_pkey'),
    postgresql_ignore_search_path=False
    )
    op.create_table('town',
    sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
    sa.Column('city_id', sa.INTEGER(), autoincrement=False, nullable=False),
    sa.Column('created_at', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=False),
    sa.Column('name', sa.VARCHAR(length=10), autoincrement=False, nullable=False),
    sa.ForeignKeyConstraint(['city_id'], ['city.id'], name='town_city_id_fkey'),
    sa.PrimaryKeyConstraint('id', name='town_pkey')
    )
    # ### end Alembic commands ###

보면 upgrade와 downgrade 두 가지에 대한 스크립트가 나와있습니다.

이렇게 하기 위한 조건이 메타데이터입니다. migrations/env.py를 보면

def run_migrations_online() -> None:

  ...

    with connectable.connect() as connection:
        context.configure(connection=connection, target_metadata=target_metadata)

target_metadata가 있는데, 데이터베이스 세팅 시 정의했던 Base의 메타데이터를 넣어줘서 연결시켜주는 것입니다.

즉, 이렇게 alembic을 통해 DB로 연결해줘야 접근해서 변경사항에 대한 감지 및 적용을 해줄 수 있는 것입니다.

공식문서에는 아래와 같이 나와있습니다.

from myapp.mymodel import Base
target_metadata = Base.metadata

autogenerate의 detect 조건은 아래와 같습니다.

  • Table additions, removals. -> 테이블 추가/삭제
  • Column additions, removals. -> 컬럼 추가/삭제
  • Change of nullable status on columns. -> nullable 상태 변경
  • Basic changes in indexes and explicitly-named unique constraints -> 인덱스 및 제약 조건 변경 사항
  • Basic changes in foreign key constraints -> 참조키 제약 조건 변경 사항

'Database' 카테고리의 다른 글

TIL14 - DB Indexing  (0) 2022.03.05
TIL8 - Transaction(2/2)  (0) 2022.02.24
TIL8 - Transaction(1/2)  (0) 2022.02.23