본문 바로가기
Back-end

alembic을 이용해 DB 마이그레이션 하기 (2)

by 노아론 2020. 3. 18.

이번 포스트에서는

  1. DB연결을 위한 alembic.ini 를 수정하기
  2. Migration Script를 생성 및 작성하여 upgrade, downgrade Migration 하기

에 대해 다뤄본다.

 

이전 포스트를 보려면? ✋

 

 

우선, alembic.ini파일을 연다. DB경로를 설정해 줄 것 이다.

본 포스트에서는 alembic의 사용법에 집중하기 위해 별다른 설치가 없는 sqlite를 사용한다.

 

아래와 같이 추가해준다

sqlalchemy.url = sqlite:///db_file.db

만일 postgresql, mysql을 연결하고싶다면?

더보기
sqlalchemy.url = postgresql://username:password@127.0.0.1:5432

이와 같이 추가하면 된다

 

이제, alembic revision 명령을 이용하여 새로운 revision을 생성해본다

나는 example 이라는 이름으로 revision을 지정해주었다.

(venv) $ alembic revision -m "example"
Generating /path/to/my_folder/practice/versions/f09152543072_example.py ...  done

 

f09152543072_example.py 라는 파일이 생겼고 현재까지의 디렉토리 구조는 아래와 같다

- my_folder
    - alembic.ini
    - practice
        - README  
        - env.py  
        - script.py.mako  
        - versions
            - f09152543072_example.py
    - venv

 

f09152543072_example.py 은 아래와 같이 구성되어있다.

"""example

Revision ID: f09152543072
Revises: 
Create Date: 2020-03-17 21:38:40.688600

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'f09152543072'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
    pass


def downgrade():
    pass

 

위 코드를 보면 현재의 revisiondowngrade revision 에 대한 변수가 있다

또한 빈 상태의 upgrade()downgrade() 함수를 볼 수 있다.

 

다음의 revision을 만들게 되면 해당 revision의 down_revision은 위 revision값이 될 것이다.

또한, 숙지하고 있어야 할 점이 있다.

 

upgrade() 함수는 필수적이며, downgrade()함수는 선택으로 사용하면 된다.

즉, 맨 처음의 revision에서는 upgrade()만 작성하고 downgrade()에는 지금과 같이 비워두거나, table drop과 같은 구성을 해주면 된다.

 

그럼 이제 database에 변화를 주기위해 upgrade() 함수를 채워보자

 

손님에 대한 테이블을 SQLAlchemy 를 이용해 작성해본다. (이름 컬럼의 사이즈는 50 으로 지정해주었다)

downgrade 하는 경우엔 customer 테이블을 비우는 것으로 하였다

def upgrade():
    op.create_table(
        'customer',
        sa.Column('id', sa.Integer, primary_key=True),
        # 다른 손님과 식별 위한 고유키 id
        sa.Column('firstname', sa.String(50), nullable=False),
        # 이름
        sa.Column('lastname', sa.String(50), nullable=False),
        # 성
        sa.Column('recentvisit', sa.DateTime)
        # 최근 방문일자
    )

def downgrade():
    op.drop_table('customer')

 

그리고 이제 migration을 해본다

head는 가장 상위의 revision으로 향하는 tag이다

(venv) $ alembic upgrade head
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> f09152543072, example

 

이제 우리가 사용하는 db파일인 db_file.db를 확인해보자

기존에 db_file.db가 없더라도 alembic upgrade head 명령을 통해 파일이 생성됨을 확인 할 수 있다

mysql, postgresql와 같은 경우 DB세팅을 해주고 시작하면 된다

image

테이블과 컬럼들이 성공적으로 구성됨을 알 수 있다.

 

그럼 이제, 두번째 revision 파일을 만들어보자

기존 customer 테이블에서 middlename 컬럼을 추가할 것이다

따라서 가독성있게 revision 이름을 "add a middlename" 으로 정해 생성해본다.

(venv) $ alembic revision -m "add a middlename"
Generating /path/to/my_folder/practice/versions/5e13c5f76fac_add_a_middlename.py ...  done

 

5e13c5f76fac_add_a_middlename.py 파일은 아래와 같이 구성되어있다.

"""add a middlename

Revision ID: 5e13c5f76fac
Revises: f09152543072
Create Date: 2020-03-17 22:10:31.522687

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '5e13c5f76fac'
down_revision = 'f09152543072'
# down_revision이 우리가 처음 생성한 "example" revision임을 알 수 있다.
branch_labels = None
depends_on = None


def upgrade():
    pass


def downgrade():
    pass

 

upgrade() 함수에는 middlename 컬럼을 추가해주고

downgrade() 함수에는 처음 revision인 example의 상태로 돌아가기 위해 middlename 컬럼을 drop하도록 구성하였다

def upgrade():
    op.add_column('customer', sa.Column('middlename', sa.String(50)))

def downgrade():
    with op.batch_alter_table('customer') as batch_op:
        batch_op.drop_column('middlename')

sqlite에는 ALTER와 DROP을 지원하지 않기 때문에 위와 같은 방법으로 컬럼을 제거하였다.

mysql, postgresql 에서는 아래와 같이 하면 된다

def downgrade():
    op.drop_column('customer', 'middlename')
# sqlite은 지원X

 

이제 alembic upgrade head 명령을 통해 migration을 진행해본다

(venv) $ alembic upgrade head
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade f09152543072 -> 5e13c5f76fac, add a middlename

 

아래와 같이 middlename컬럼이 추가됨을 확인 할 수 있다

image

 

alembic의 migration 기록(history)을 보고싶으면 alembic history 명령을 통해 확인 가능하다

(venv) $ alembic history
f09152543072 -> 5e13c5f76fac (head), add a middlename
<base> -> f09152543072, example

 

이제, downgrade를 수행해보도록 한다

downgrade는 upgrade와는 달리 head를 사용할 수 없다

Partial Revision Identifiers 혹은 Relative Migration Identifiers 의 방법으로 downgrade 할 수 있다.

upgrade 경우에서도 사용 가능하다

alembic downgrade f09152543072
# Partial Revision Identifiers는 revision번호를 입력하는 방법이다 (절대적 위치)

alembic downgrade -1
# Relative Migration Identifiers는 상대적인 위치의 이동이 가능하다
# -2도 물론 가능하다. 지금 상황의 경우엔 -2는 drop customer table의 결과를 가지게 된다

 

따라서, alembic downgrade -1 이나 alembic downgrade <down_revision의 값> 으로 입력해야한다

alembic downgrade -1 명령으로 downgrade 해본다

(venv) $ alembic downgrade -1
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running downgrade 5e13c5f76fac -> f09152543072, add a middlename

 

이제 customer 테이블에서 middlename 컬럼이 사라진 것을 볼 수 있을 것이다.

이것으로 alembic.ini를 수정하여 DB연결하기, Migration Script를 생성 및 작성하여 upgrade, downgrade 하기 를 모두 마쳤다.

 

다음 포스트에서는 ForeignKey 컬럼을 나타내고 migration하는 방법에 대해 다룬다

 

이 글이 도움이 되셨다면 공감버튼 부탁드립니다

댓글