migration(마이그레이션)이란
장고에서 모델과 연결된 DB의 버전을 관리하는 방법이다. migration은 파이썬 파일 형식으로 관리된다.
migration의 특징
- 실제 DB에서 변경되는 내용이 없어도 migration 파일이 만들어질 수 있다.
- 어떤 DB에는 적용 가능한 내용이 다른 DB에는 적용 불가능할 수 있다. (MySQL의 경우 PostgreSQL보다 컬럼에 사용하는 max_length 속성의 최댓값이 작다)
- 직접 migration 파일을 수정할 수 있고 빈 migration 파일을 만들 수도 있다.
- transaction 개념이 있는 DB(postgresql, sqlite)의 경우, migration은 하나의 transaction 안에서 실행된다. 그렇지 않은 경우는 transaction 없이 실행되고, 이 경우 migration 도중 failure가 발생하면 rollback이 되지 않는다.
- 맨 처음 만들어진 migration(initial migration)이 아닌 경우, migration은 다른 migration에 의존한다.
migration이 만들어질 때
python manage.py makemigrations 커맨드를 입력하면 migration 파일이 만들어진다.
migration 파일에는 여러 속성들이 있지만, 그 중에서도 dependencies와 operations가 대표적이다.
dependencies는 해당 migration이 다른 어떤 migration에 의존하고 있는지를 나타낸다.
operations는 해당 migration이 해당 앱의 모델을 어떻게 변형할지를 나타낸다.
makemigrations 명령어에 따라 migration 파일이 만들어지는 원리
- 장고는 이전에 있던 migration들을 순서대로 실행한다.
- 현재 모델의 상태와 1번의 과정에서 얻은 모델의 상태를 비교한다. 만약 변화된 점이 없다면 'detected no changes'와 유사한 문구가 뜬다.
- 2번에서 현재 모델과 migration 파일들을 순차적으로 실행하면서 얻은 모델의 상태에 차이가 있다면, 그 차이점을 바탕으로 migration 파일을 만든다.
migration 관련 명령어들
- makemigrations: 위의 과정으로 migration 파일을 만든다.
- migrate: makemigrations으로 만들어진 파일이 있는 경우 해당 내용을 실행해서 DB 스키마를 바꾼다. 만약 모델에 변화가 있는데 makemigrations 없이 migrate를 실행한 경우, migration 파일이 만들어지고 그 파일에 대해서 바로 migrate 명령어가 이어서 실행된다.
- sqlmigrate: migrate와 똑같이 동작하는데, 다만 동작 과정에서 어떤 SQL문이 실행되는지를 보여준다.
- showmigrations: 현재 어떤 migration들이 있는지를 보여준다. migration 파일은 있는데 DB에 반영되지 않은 경우에는 체크 표시가 없고, migration 파일도 있고 DB에 정상적으로 반영된 경우 체크 표시가 있다.
- squashmigrations: 기존에 있던 여러 개의 migration 파일을 압축하는 커맨드이다.
apply migration
python manage.py migrate {app_label}
특정 앱에 대해서만 migration을 적용하고 싶을 때 사용한다.
reverse migration
python manage.py migrate {app_label} {number/migration name}
특정 앱에 대해서 이전 migration으로 진행 상태를 돌리고 싶을 때 사용한다. migration의 번호를 입력하면 해당 번호까지의 migration이 실행된 상태로 돌려 준다.
물론 항상 가능한 것은 아니고, 되돌리지 못하는 migration의 경우는 IrreversibleError가 발생할 수 있다.
squash migration
python manage.py squashmigrations {app_label} {number/migration name}
기존 여러 개의 migration 파일을 1개 혹은 몇 개로 줄이는 작업이다. 최초 migration부터 입력한 번호까지의 migration을 압축한다고 볼 수 있다. 기존 migration보다 파일의 개수나 operation의 개수는 줄어들지만 DB에 적용되는 내용은 똑같다.
작업 원리
- squash 대상이 되는 모든 migration에서 operation을 추출해서 순서대로 정렬한다.
- 1번 결과에 대해 optimizer를 실행해서, 중복되는 operation은 생략하는 등 operation의 개수를 줄인다. (ex. CreateModel과 DeleteModel이 같이 있다면 두 operation 모두 삭제하기)
- 2번의 결과를 migration 파일로 만든다.
squashed migration -> normal migration
squashed migration(squashmigration의 결과로 생성된 파일)은 해당 파일의 replace 속성이 있어서 일반 migration과는 달리 "기존의 migration을 대체한" 파일이다.
이 파일이 일반 migration처럼 동작하게 하려면 추가 작업이 필요하다.
- squashmigrations 명령어 실행하기
- 1번의 migration 파일이 대체한 기존 migration 파일들 삭제하기
- 2번에서 삭제한 migration 파일에 의존하는 다른 파일들의 dependencies 속성을 1번에서 새로 생성된 squashed migration 파일로 수정하기
- 1번 파일에 표시된 replaces 속성을 삭제하기
fake migration
이미 DB에는 SQL문이 실행되어 테이블과 컬럼이 있으나 장고 migration에서는 반영되지 않았을 때 --fake 옵션을 사용한다.
즉 장고에서 관리하는 migration의 진행 상태만 진행한 것으로 변화시키고, 실제로 DB에 SQL문은 실행하지 않는 것을 fake migration이라고 한다.
initial migration
맨 처음 실행되는 mgiration으로, 다른 migration에 의존하지 않는다.
보통 initial migration은 1개이지만 2개 이상의 initial migration을 만들 수도 있다.
--fake-initial 옵션을 붙이면 이미 DB에서 테이블과 컬럼이 만들어진 경우 초기 migration을 적용하지 않고 스킵할 수 있다. 다만 이 옵션은 적용하려고 했던 initial migration에 선언된 모델이 DB에 존재하는지가 확인되어야 적용할 수 있다. (적용하려는 모델이 없는데 --fake-initial 옵션을 쓸 수는 없다.)
RunPython
기존의 migration 파일을 작성하는 방법이 아니라, python 코드로 DB 내부의 내용을 변경할 수 있다.
(RunPython과 비슷하게는 RunSQL도 있다. 이 경우 SQL문을 직접 장고에서 실행할 수 있다.)
주의 사항
1. RunPython으로 현재 앱이 아닌 다른 앱에 있는 모델에 접근할 경우, migration 파일의 dependencies 속성에다 다음 2가지를 꼭 추가해야 한다.
- 현재 app의 initial migration
- 접근하는 다른 앱의 가장 최신 migration
그렇지 않으면 LookupError 에러가 발생한다.
2. RunPython으로 data migration 작업을 할 수 있다.
- python manage.py migrate {app_label} --empty 커맨드로 빈 migration 파일을 만든다.
- 해당 파일의 dependencies 속성에는 해당 앱의 initial migration만 추가한다.
- operations에는 migrations.RunPython()을 명시하고, 괄호 안에는 callable(실행 가능한 함수의 이름)을 적는다. data migration 작업을 하는 함수를 만들고 그 함수의 이름을 callable로 적으면 된다.
'server-side > Django' 카테고리의 다른 글
django customizing authentication (0) | 2024.01.07 |
---|---|
django sessions (0) | 2024.01.06 |
django routers (1) | 2023.12.21 |
django apps (0) | 2023.12.20 |
models and databases (0) | 2023.09.16 |