migration(마이그레이션)이란

장고에서 모델과 연결된 DB의 버전을 관리하는 방법이다. migration은 파이썬 파일 형식으로 관리된다. 

 

migration의 특징

  1. 실제 DB에서 변경되는 내용이 없어도 migration 파일이 만들어질 수 있다. 
  2. 어떤 DB에는 적용 가능한 내용이 다른 DB에는 적용 불가능할 수 있다. (MySQL의 경우 PostgreSQL보다 컬럼에 사용하는 max_length 속성의 최댓값이 작다)
  3. 직접 migration 파일을 수정할 수 있고 빈 migration 파일을 만들 수도 있다. 
  4. transaction 개념이 있는 DB(postgresql, sqlite)의 경우, migration은 하나의 transaction 안에서 실행된다. 그렇지 않은 경우는 transaction 없이 실행되고, 이 경우 migration 도중 failure가 발생하면 rollback이 되지 않는다. 
  5. 맨 처음 만들어진 migration(initial migration)이 아닌 경우, migration은 다른 migration에 의존한다. 

 

migration이 만들어질 때

python manage.py makemigrations 커맨드를 입력하면 migration 파일이 만들어진다. 

migration 파일에는 여러 속성들이 있지만, 그 중에서도 dependencies와 operations가 대표적이다. 

dependencies는 해당 migration이 다른 어떤 migration에 의존하고 있는지를 나타낸다. 

operations는 해당 migration이 해당 앱의 모델을 어떻게 변형할지를 나타낸다. 

 

makemigrations 명령어에 따라 migration 파일이 만들어지는 원리

  1. 장고는 이전에 있던 migration들을 순서대로 실행한다. 
  2. 현재 모델의 상태와 1번의 과정에서 얻은 모델의 상태를 비교한다. 만약 변화된 점이 없다면 'detected no changes'와 유사한 문구가 뜬다. 
  3. 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에 적용되는 내용은 똑같다. 

 

작업 원리

  1. squash 대상이 되는 모든 migration에서 operation을 추출해서 순서대로 정렬한다. 
  2. 1번 결과에 대해 optimizer를 실행해서, 중복되는 operation은 생략하는 등 operation의 개수를 줄인다. (ex. CreateModel과 DeleteModel이 같이 있다면 두 operation 모두 삭제하기)
  3. 2번의 결과를 migration 파일로 만든다. 

 

squashed migration -> normal migration

squashed migration(squashmigration의 결과로 생성된 파일)은 해당 파일의 replace 속성이 있어서 일반 migration과는 달리 "기존의 migration을 대체한" 파일이다. 

이 파일이 일반 migration처럼 동작하게 하려면 추가 작업이 필요하다. 

  1. squashmigrations 명령어 실행하기
  2. 1번의 migration 파일이 대체한 기존 migration 파일들 삭제하기
  3. 2번에서 삭제한 migration 파일에 의존하는 다른 파일들의 dependencies 속성을 1번에서 새로 생성된 squashed migration 파일로 수정하기
  4. 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 작업을 할 수 있다. 

  1. python manage.py migrate {app_label} --empty 커맨드로 빈 migration 파일을 만든다. 
  2. 해당 파일의 dependencies 속성에는 해당 앱의 initial migration만 추가한다. 
  3. 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

+ Recent posts