[230310 - TIL] Django - 이전 마이그레이션 파일이 없을 때

Dongwoo Kim·2023년 3월 10일
0

TIL / WIL

목록 보기
92/113

1. 개요

팀에서 공동으로 사용 중인 django 프로젝트에 내가 작성한 모델을 DB에 추가해야했다. 그런데 migrations 파일들이 .gitignore에 해당하여 이전 마이그레이션파일이 없는 상태로 나의 모델을 DB에 추가하려고하니 python manage.py makemigrations my_app 을 실행하니 에러가 발생하였다. 이에 대한 원인과 해결한 방법에 대해 알아보자.


2. 예상 시나리오

django 프로젝트에 이미 my_app이라는 앱에 article이라는 모델을 DB에 마이그레이션한 상태라고 가정하자.

1) article 모델을 DB에 마이그레이션할 때 python [mange.py](http://maange.py) makemigrations my_app 명령어를 통해 생성한 파일을 0001_initail.py 라고하자.

2) 프로젝트에 기능을 추가하면서 article 모델에 여러 수정이 일어났고 맨 마지막 마이그레이션 파일이 0045_some_coding.py 라고하자

3) 이제 나는 article 모델을 foreignKey로 참조하는 comment라는 모델을 새로 만들어서 DB에 추가하고싶다. 0001_initial.py 부터 0045_some_coding.py 까지의 마이그레이션 파일이 나에게는 없는 상황이다. 이때 내가 comment를 DB에 추가하기위해 comment 모델에 대한 마이그레이션 파일을 0046_my_app_comment.py 라는이름으로 만들고 python [manage.py](http://manage.py) makemigrations my_app 명령어를 실행하자 에러가 발생한다.

  • 모델 구조
    # my_app/models.py

    # 기존에 정의되어있던 article 모델
    class Article(models.Model):
        title = models.CharField(max_length=250)
    	content = models.TextField()
   
    # 이번에 작업한 comment 모델
    class Comment(models.Model):
    	content = models.TextField()
    	article = models.ForeignKey(Article, on_delete=models.CASCADE)
  • 내가 추가하고 싶었던 마이그레이션 파일
    # my_app/migrations/0046_my_app_comment.py
  
    class Migration(migrations.Migration):
      
        dependencies = [
    			('my_app', '0045_some_coding.py')
        ]
   
        operations = [
            migrations.CreateModel(
                name='Comment',
                fields=[
                    ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                    ('content', models.TextField()),
                    ('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='place.article')),
                ],
            ),
        ]

3. 원인

원인은 comment가 article 모델을 참조하고있지만 현재 나에게는 이전 마이그레이션 파일, 즉 DB에 대한 정보파일이 없기 때문에 article을 참조할 때 에러가 발생하는 것이다.

만약 외부모델을 참조하지않는 comment 내부필드만 존재했을 경우 makemigrations 에서 에러가 발생하지는 않았을 것이다. 다만 이 경우 마이그레이션파일이 만들어졌다고 하더라도 migrate 명령어를 실행할 경우 제대로 작동하지않을 확률이 매우 높다. 그 이유에 대해서도 같이 알아보자.


4. 해결방법

마이그레이션파일은 쉽게 말해 DB 테이블의 변화 과정을 나타낸다. 마이그레이션할 때마다 현재 수정한 DB 상태가 이전과 무엇이 달라졌는지를 마이그레이션 파일을 통해 알 수 있는 것이다. 따라서 0001_initail.py 부터 0045_some_coding.py 까지의 기록을 모두 반영하면 현재 DB의 상태가 되는 것이다.


4-1) 내가 작업하기전의 마이그레이션 파일를 만든다

따라서 내가 작업하기전 DB에 대한 마이그레이션 파일을 만들어야 한다. 마이그레이션파일이 하나도 없는 상태에서 python manage.py makemigrations my_app 실행하면 0001_initail.py 라는 파일이 만들어지고 여기에는 현재 모델에 대한 정보가 반영되어있다. 여기서 내가 작업하기 전의 마이그레이션 파일을 만들기위해 일단 comment에 대한 마이그레이션 정보를 삭제한다. 그러면 일단 0001_initail.py 부터 0045_some_coding.py 의 정보, 즉 현재 DB 상태에 대한 정보가 방금 만든 0001_initail.py 에 모두 반영되어있다고 할 수 있다.

  • python manage.py makemigrations my_app 로 생성되는 0001_initial.py 파일
    : 현재 모델에 대한 정보가 모두 있다.
    class Migration(migrations.Migration):

        initial = True
   
        dependencies = [
        ]
   
        operations = [
            migrations.CreateModel(
                name='Article',
                fields=[
                    ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                    ('title', models.CharField(max_length=250)),
                    ('content', models.TextField()),
                ],
            ),
            migrations.CreateModel(
                name='Comment',
                fields=[
                    ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                    ('content', models.TextField()),
                    ('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='place.article')),
                ],
            ),
        ]
  • 현재 DB 상태에 대한 마이그레이션 파일
    : 내가 작업했던 Comment 모델에 대한 정보만 빼주면된다.
    # my_app/migrations/0001_initial.py
   
    class Migration(migrations.Migration):
   
        initial = True
   
        dependencies = [
        ]
   
        operations = [
            migrations.CreateModel(
                name='Article',
                fields=[
                    ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                    ('title', models.CharField(max_length=250)),
                    ('content', models.TextField()),
                ],
            ),
        ]

4-2) 내가 작업한 내용에 대한 마이그레이션 파일을 만든다

이번에는 반대로 내가 작업한 내용에 대한 것만 마이그레이션 파일로 만들어보자. 아까 python manage.py makemigrations my_app 해서 만들어졌던 파일에서 반대로 내가 작성한 내용의 정보만 남기고 나머지를 삭제하고 이전 파일에 대한 참조 정보를 넣어주면 된다.. 그리고 0001_initail.py 파일은 아까 만들었으니 이름은 대충 0002_my_app_comment.py 라고 지어보자

  • 내가 작업한 내용에 대한 마이그레이션 파일
    # my_app/migrations/0002_my_app_comment.py
   
    class Migration(migrations.Migration):
        dependencies = [
    			('my_app', '0001_initail.py')
        ]
   
        operations = [
            migrations.CreateModel(
                name='Comment',
                fields=[
                    ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                    ('content', models.TextField()),
                    ('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='place.article')),
                ],
            ),
        ]

4-3) 바로 마이그레이션 하기?

현재 DB에 대한 정보도 마이그레이션 파일로 담았고 내가 작업했던 내용도 마이그레이션 파일로 만들었기 때문에때문에 바로 python [manage.py](http://manage.py) migrate my_app 명령어를 실행하면 DB에 적용될 것 같다! → 물론 잘 실행될 수 있지만 추후 문제가 생길 확률이 매우 높고, 극히 드물게 다음과 같이 변화가 없다고 할수도있다.

난 분명히 새로운 마이그레이션 파일을 만들었는데 . 왜그런걸까?


4-4) django는 마이그레이션 파일 이름만 알고있을뿐...

DB에 가서 django_migrations 라는 테이블을 보자

이런 데이터들이 있다. 이게 뭘까?
우리가 pyhon manage.py migrate my_app 명령어를 실행하면 django는 해당 마이그레이션 파일 내용을 DB에 적용시키고 현재까지의 마이그레이션파일의 이름을 django_migrations라는 테이블에 저장해놓는다. 그리고 나중에 다시 마이그레이트 명령어가 실행되면 이곳에 저장된 파일 이름의 마이그레이션 파일은 이미 적용했다고 그 외의 파일을 적용시킨다.

즉, 사전에 우리 프로젝트는 이미 0001_initail.py 부터 0045_some_coding.py 까지의 마이그레이션 파일이 적용되었고 django는 django_migrations를 통해 이 이름들의 마이그레이션 파일을 제외한 나머지 파일들에 대해서 마이그레이트한다. 따라서 내가 4-2)에서 만든 0001_initial.py 은 무시할 것이고 0002_my_app_comment.py 라는 파일을 적용할 것인데 해당 팔이 0001_initial.py 을 참조하고 있으니 해당 파일의 내용부터 차례대로 DB에 적용할 것이다. 여기서는 두개의 파일만 고려했지만 참조하는 파일이 많아진다면 마이그레이션 파일간의 이름이 기존에 적용했던 마이그레이션 파일 0002_라는 번호가 겹치므로과 혼동을 야기시킬 수 있다.


4-5) 그렇다면 최대한 혼동을 줄일 수 있는 방법은?

최대한 혼동을 줄일 수 있는 방법으로는 마이그레이션 파일 이름을 새로운 번호로 설정하는 것이다. 즉 0002_my_app_comment.py 로 지었던 이름을 0046_my_app_comment.py 이런 식으로 지어보자. 그리고 pyhon manage.py migrate my_app 를 실행하면 다음과 같이 django_migrations 테이블에 다음과 같이 데이터가 추가된다.

이러면 다른 개발자가 보더라도 새로운 마이그레이션 파일이 추가되었음을 알 수 있고 헷갈리지않고 최신화를 유지할 수 있을 것이다.

profile
kimphysicsman

0개의 댓글