본문 바로가기

Python/Frameworks.Libraries

Django 테이블 삭제하는 방법. django.db.utils.OperationalError: no such table 오류 해결 방법

Intro

Django 로 개발을 하면서 자주 TABLE( 혹은 Model, 섞어서 표현하겠음. )을 삭제할 때 Migration 에 대한 개념이 별로 없어서인지 django.db.utils.OperationalError: no such table 에러를 자주 만나게되었습니다.

이번에도 한 번 그런 에러가 발생해서 이번 기회에 한 번 정확한 해결방법 및 Django 에서 Model을 삭제하는 방법에 대해 정리해보려합니다.

요점

중요한 점은 django ORM (Database를 직접 다루는 게 아니라 Django에서 api를 통해 다루는 방식 ) 에서

python manage.py makemigrtions 는 DB에 migrate할 변동내역을 적어놓기만하는 것이고

실제 DB에 그 내용이 반영되는 것은

python manage.py migrate 를 통해서만! 입니다.

migration에 대한 좀 더 자세한 내용은 초보몽키 블로그 에 나와있는데, 궁금하시면 참고해보세요.

변동사항들이 적힌 migration files를 통해 롤백할 앞 뒤로 롤백할 수도 있습니다. 따라서 간혹 migration files를 통째로 지워서 TABLE을 지워버리는 경우도 있기는 한데, 조심해야할 수도 있다고 하네요. ( 롤백을 못해버리니까? )

django.db.utils.OperationalError: no such table

주로 이 에러는 django ORM을 통해서가 아니라 DB shell 을 통해 직접 TABLE을 삭제할 경우 발생하는 것 같아요. 아직 Model, 즉 TABLE 을 어떻게 삭제하는 지 몰라서 django로 뚱땅거리다가 *에라모르겠다; 하고 DB에 가서 직접 DROP TABLE name; * 을 때려버리는 거죠.

models.py에서도 model을 삭제해서 migrations에 적을 변동사항이 생김.
makemigraions까지는 성공하는데 migrate하면 no such table 오류 남!

그리고 나서 이제 makemigations 를 하면 - Delete Model ... 이라며 성공적인 문구를 발견하고 기분이 넘 좋아질 수 있지만, 그것도 잠시 migrate를 하면 다시 django.db.utils.OperationalError: no such table 에러가 발생합니다.

원인

migrate 는 기본적으로 자신이 가장 마지막으로 migrate한 이후의 migration file 부터 migrate를 진행합니다. 변동사항을 DB에 적용한다는 거죠. 근데 DROP TABLE은 내가 이미 직접 진행했죠.

하지만 이후 models.py에서도 model을 주석처리하든 없애든 했으니 migration file에는 해당 TABLE을 지우라는 migration file을 만듭니다.

그리고나서 migrate 하려는데 지우라는 TABLE이 이미 지워져있으니 지울 게 없어서 no such table 에러가 발생하는 거죠.

해결방법

TABLE을 삭제하려는데 django.db.utils.OperationalError: no such table 오류가 난 경우

  1. models.py에서 삭제할 model의 코드를 없애고

    python manage.py makemigrations 를 통해 migration file을 만든다.

    No changes Detected가 떠도 괜찮다. 보통은 Delete model ...가 뜰 것이다.

  2. python manage.py migrate --fake 를 입력한다.

    이게 뭐냐면 변동사항이 적힌 migration을 진행한 척 하는 겁니다. 쉽게 말해서 나중에 실행해야할 migraion file index를 건너뛰는 느낌. 실행하지 않았지만, index는 진행시키는 느낌.

  3. 이후에 자유롭게 원하는 작업 하시면 됨.

작업의 순서가 중요! migrate --fake는 그 동안 만들어진 migrations file을 뛰어넘는 것이기 때문에 migrate 를 입력한 뒤 migrate --fake를 입력한다거나 하면 아무 효과가 없기 떄문에, 위의 순서를 지켜주는 것이 중요합니다.

너무 다양한 케이스가 있어서 자세히 적기는 힘드네요. 거의 시뮬레이션 급이라.

Django 에서 Model을 삭제하는 가장 좋은 방법

가장 좋은 방법은 아무래도 Django ORM 그대로를 이용하는 것입니다. 다만 Django 에서 삭제되는 TABLE에 대한 Backup은 지원하지 않으니 필요한 경우 알아서 백업해야합니다.

  1. models.py 에서 삭제할 model의 코드를 주석처리한다. (나중에 오류났을 때 다시 써야하는 경우도 있어서 지우는 것 보다는 주석이 나음)

  2. admin.py 및 다른 models.py등등에서 ForeignKeyManyToMany로 지우려는 model을 참조하는 경우를 다 지운다.

  3. python manage.py makemigrations 입력!

    `- Delete talbe ...` 이 떠야함

  4. python manage.py migrate 로 migrtaion file의 내용 DB에 반영.

예시

아래와 같은 models.py에서 직접 DROP TABLE을 하고 ( 예시에서는 SQLite3를 이용함. ) models.py 에서 model 코드를 주석처리하면 DBShell에서 TABLE이 삭제되고, makemigrations까지는 성공적이지만 migrate는 에러가 발생함.

따라서 python manage.py migrate --fake를 입력해주면 내가 이미 migration에 적힌 변동내역을 직접 진행했었고, 따라서 migrtaion에 적인 내용을 python manage.py migrate에서는 fake로 실행하여 오류가 발생하지 않고 다음의 어떤 작업이든 수행할 수 있습니다.

이번 예시에 사용될 models.py. 주석처리 될 것임.
초기상태. TABLE이 우측 하단에 존재하고 있음.
DB shell 에서직접 TABLE 삭제
makemigrations 까지는 성공
하지만 migrate시 오류 발생
 python manage.py migrate --fake 로 해결.

이제 테이블을 성공적으로 삭제했고, 내용을 반영했으니, 이후에 다른 작업을 원활히 수행할 수 있나 보겠습니다.

다시 School Model을 생성하고 makemigrations, migrate를 진행하였더니 문제없이 잘 작동하네요.

배운 점

TABLE을 지우는 것은 쉽지 않은 일입니다. 특히나 Schema가 복잡해질 수록, 한 테이블을 잘못 지웠다가는 의존성과 CASCADE에 의해 주루룩 테이블들이 다 지워질 수도 있을 것 같은데, 이번에 좀 명확히 어떻게 TABLE을 지우는 지 알게 된 것 같아 다행입니다.
잘못 지우는 작업을 수행한 Schema는 다시 복구하기도 힘들 수도 있습니다..

가장 좋은 것은 django 에서의 migration에 대한 의미를 정확하게 알게되어 다행이네요.