brunch

You can make anything
by writing

C.S.Lewis

by 서환수 Jan 11. 2024

Alembic 활용

Python에서 SQLAlchemy로 개발하기

Python에서 DB를 사용할 때는 SQLAlchemy + Pydantic을 많이들 사용합니다. FastAPI + SQLAlchemy + Pydantic으로 REST API를 만드는 작업을 하는데, DB 구조를 변경하는 일이 종종 있다면 Alembic을 쓰는 게 좋습니다. Alembic은 SQLAlchemy와 함께 사용하는 용도로 만들어진 데이터베이스 이전 툴입니다.


DB를 활용하는 개발을 하다 보면 제 아무리 데이터 모델링에 공을 들인다고 하더라도 시간이 지남에 따라 데이터베이스 테이블 구조에 변화가 생길 수 밖에 없습니다.이런 경우에 데이터베이스 이전(migration)을 깔끔하게 문서화할 수 있는 방안이 필요한데, ORM으로 SQLAlchemy을 쓰는 경우에는 Alembic을 가장 많이 씁니다.


항상 alembic을 도입해야 하는데 생각만 하다가 DB를 고쳐볼 생각을 하면서 alembic을 먼저 적용해 봤습니다. 이미 테이블을 몇 개 만들어서 쓰고 있었고, ORM으로 건드리지 않을 테이블도 많이 들어있는 상황이라 Alembic 도입이 더 망설여졌는데, 직접 해 보니 별로 어렵진 않더군요.


방법은 간단합니다.


1. Alembic 설치

pip install alembic


2. Alembic 초기화

프로젝트 루트에서 다음과 같은 명령어를 실행합니다.

alembic init alembic


3. 데이터베이스 URL 설정

alembic.ini 파일에서 sqlalchemy.url 항목을 찾아서 데이터베이스 URL을 입력해 줍니다.

sqlalchemy.url = postgresql://user:password@localhost/dbname

데이터베이스 URL을 환경변수로 설정하는 경우라면 데이터베이스 URL 부분을 빈 칸으로 남겨 둡니다.


4. env.py  수정

데이터베이스 URL을 환경변수로 설정했다면 env.py에서 config.set_main_option('sqlalchemy.url', DATABASE_URL) 같은 식으로 데이터베이스 URL을 지정해 줍니다.

또한 SQLAlchemy 모델이 들어있는 모듈을 임포트하고 SQLAlchemy의 Base 클래스도 임포트하여 이 모델의 현재 상태를 인식하도록 해야 합니다.


그리고 데이터베이스 내에 다른 프로세스나 시스템에서 관리하는 테이블이 있고, 그 테이블들은 ORM으로 건드리지 않을 거라면 Alembic에서 관심을 가지지 않도록 설정이 필요한데, 이 작업도 env.py 파일에서 처리합니다.

예를 들어서 'table_to_exclude1', 'table_to_exclude2'라는 두 테이블을 제외시킨다고 하면 env.py에 다음과 같이 include_object라는 함수를 정의합니다.

def include_object(object, name, type_, reflected, compare_to):
    if name in ['table_to_exclude1', 'table_to_exclude2']:
        return False
    else:
        return True

그리고 아래쪽으로 내려가면 run_migrations_online 함수가 있는데, 그 함수 내용을 아래와 같은 식으로 수정합니다.


def run_migrations_online():
     # ...기존 코드 ...

    # 이 부분에 include_object 함수를 추가
    with connectable.connect() as connection:
        context.configure(
        connection=connection,
            target_metadata=Base.metadata,
            include_object=include_object,  # 이 부분 추가
        )
        with context.begin_transaction():
            context.run_migrations()


이렇게 하면 ORM에서 건드리지 않을 테이블은 제껴두고 작업을 처리할 수 있습니다.


5.현재 데이터베이스 상태 기록

이미 사용 중인 데이터베이스의 현재 상태를 기록하기 위해, Alembic을 사용하여 초기 마이그레이션(revision)을 생성합니다. alembic revision --autogenerate -m "Initial migration" 명령어를 실행합니다. 이 명령어는 현재 데이터베이스 스키마를 분석하여 마이그레이션 파일을 생성합니다.


6. 마이그레이션 검토 및 수정

Alembic이 자동으로 생성한 마이그레이션 스크립트를 검토하고 필요한 경우 수정합니다. 잘 보고 엉뚱한 짓 안 하도록 수정해 줘야 합니다.


7. 마이그레이션 적용

alembic stamp head 명령으로 마이그레이션이 데이터베이스에는 적용되지 않으면서 현재 상태가 인식되도록 만듭니다.


이 단계를 모두 마치고 나면 다음부터는 일반적인 alembic 활용 절차를 거쳐서 작업할 수 있습니다.


1. SQLAlchemy 모델 수정

2. alembic revision --autogenerate -m "커밋 코멘트" 명령으로 마이그레이션 생성

3. 생성된 마이그레이션 파일 검토

4. alembic upgrade head 명령으로 마이그레이션 적용

5. (옵션) 실제 DB가 제대로 변경되었는지 확인


시작하기 전에는 좀 두려움이 있지만 한 번 해 보고 나면 별로 어렵지도 않고 DB 이전을 편하게 진행할 수 있습니다.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari