터칭 데이터

장고(Django) 모델을 수정, 마이그레이션 되돌리기 본문

장고 (Django)

장고(Django) 모델을 수정, 마이그레이션 되돌리기

터칭 데이터 2023. 10. 31. 17:17

모델 수정하기

 

테이블에 여러 형태의 데이터를 담을 수 있는 것 처럼 장고의 모델에도 여러 필드 타입이 제공됩니다.

우리가 만든 모델에 Boolean과 Float 필드를 추가해보겠습니다.

 

from django.db import models

# Create your models here.

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    is_something = models.BooleanField(default=False)
    average_score = models.FloatField(default=0.0)

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

 

우리는 여러 가지의 필드 타입을 살펴보고 추가함과 동시에 Question 모델을 수정한 셈이기도 합니다.

 

모델을 생성하는 것은 저번 시간에 살펴보았습니다. 그렇다면 수정은 어떻게 할까요?

 

 

 

상당부분은 생성과 똑같습니다.

 

실행할 마이그레이션을 만들고

python manage.py makemigrations

 

만든 마이그레이션으로 마이그레이트를 진행합니다.

python manage.py migrate

 

 

위 두 단계를 적용하면 다음과 같습니다.

(DjangoProjects) C:\Users\User\DjangoProjects\Scripts\mysite>python manage.py makemigrations
Migrations for 'polls':
  polls\migrations\0002_question_average_score_question_is_something.py
    - Add field average_score to question
    - Add field is_something to question

(DjangoProjects) C:\Users\User\DjangoProjects\Scripts\mysite>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Applying polls.0002_question_average_score_question_is_something... OK

정상적으로 average_score와 is_something 필드들이 question 모델에 추가가 되었습니다.

 

잘 보면 마이그레이션이 0002로 진행되었다고 뜨는데 0002를 기억해두시기를 바랍니다.

 

장고로는 모델, 마이그레이션, 테이블화가 정상적으로 진행되었지만

실제로 DB상에서도 테이블이 잘 만들어지고 작동하는지 확인을 해보려 합니다.

 

 

 

 

 

SQLite3

장고는 자체적으로 SQLite3라는 DB를 제공합니다.

실제 많이 사용되지는 않지만 MySQL, ORACLE 등 메이저 RDBMS와 크게 다르지 않고 장고 학습을 진행하는데 크게 문제는 없습니다. 사용자가 원하지 않는다면 설정을 바꿔 얼마든지 다른 DB로 바꿔 사용할 수 있습니다.

 

SQLite3로 만들고 수정한 테이블들을 확인해 봅시다.

 

 

프로젝트 mysite안에는 db.sqlilte3라는 파일이 존재합니다. VSCode와 같은 텍스트 에디터로 열람되지는 않는데

이 파일은 장고 shell에서 sqlite3 DB에 접속할 수 있도록 도와주는 역할을 합니다.

 

터미널 프로젝트 디렉토리(mysite)에서 sqlite3 db.sqlite3를 입력하면

(DjangoProjects) C:\Users\User\DjangoProjects\Scripts\mysite>sqlite3 db.sqlite3
SQLite version 3.40.1 2022-12-28 14:03:47
Enter ".help" for usage hints.
sqlite>

sqlite DB로 접속합니다.

 

 

.tables를 입력하면

sqlite> .tables
auth_group                  django_admin_log
auth_group_permissions      django_content_type
auth_permission             django_migrations
auth_user                   django_session
auth_user_groups            polls_choice
auth_user_user_permissions  polls_question

모든 테이블들 조회합니다.

 

여기서 테이블 명들의 형식이 OO_XX인데

예를 들어 polls_choice는

polls라는 앱의 choice라는 테이블이 있다는 뜻입니다.

 

우리가 만든 polls 앱의 choice 테이블(polls_choice)과 questons 테이블(polls_question)이 보입니다.

 

django_migrations라는 테이블이 보이는데

이를 조회해보면

sqlite> select * from django_migrations;
1|contenttypes|0001_initial|2023-10-31 06:44:01.336592
2|auth|0001_initial|2023-10-31 06:44:01.391067
3|admin|0001_initial|2023-10-31 06:44:01.409164
4|admin|0002_logentry_remove_auto_add|2023-10-31 06:44:01.434150
5|admin|0003_logentry_add_action_flag_choices|2023-10-31 06:44:01.450149
6|contenttypes|0002_remove_content_type_name|2023-10-31 06:44:01.479140
7|auth|0002_alter_permission_name_max_length|2023-10-31 06:44:01.500535
8|auth|0003_alter_user_email_max_length|2023-10-31 06:44:01.516526
9|auth|0004_alter_user_username_opts|2023-10-31 06:44:01.526519
10|auth|0005_alter_user_last_login_null|2023-10-31 06:44:01.543510
11|auth|0006_require_contenttypes_0002|2023-10-31 06:44:01.550024
12|auth|0007_alter_validators_add_error_messages|2023-10-31 06:44:01.561017
13|auth|0008_alter_user_username_max_length|2023-10-31 06:44:01.579007
14|auth|0009_alter_user_last_name_max_length|2023-10-31 06:44:01.596997
15|auth|0010_alter_group_name_max_length|2023-10-31 06:44:01.611988
16|auth|0011_update_proxy_permissions|2023-10-31 06:44:01.623982
17|auth|0012_alter_user_first_name_max_length|2023-10-31 06:44:01.639703
18|polls|0001_initial|2023-10-31 06:44:01.658544
19|sessions|0001_initial|2023-10-31 06:44:01.671536
20|polls|0002_question_average_score_question_is_something|2023-10-31 07:11:36.349556

우리가 진행했던 마이그레이션에 대한 기록들이 저장되고 있음을 알 수 있습니다.

 

 

이번에는 우리가 수정한 polls_question 테이블의 구조를 살펴보겠습니다.

SQLite3에서 테이블의 구조 확인은 .schema (테이블명)입니다.

sqlite> .schema polls_question
CREATE TABLE IF NOT EXISTS "polls_question" 
    ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, 
    "question_text" varchar(200) NOT NULL, 
    "pub_date" datetime NOT NULL, 
    "average_score" real NOT NULL, 
    "is_something" bool NOT NULL);

id, question_text, pub_date와 같은 처음에 테이블을 만들 때 있던 필드들에 더해

average_score, is_something과 같이 이번에 추가해준 필드(컬럼)들 역시 스키마로 포함되어 있음을 확인할 수 있습니다.

(여기 SQLite3에서는 float 타입이 real로 적혀있군요.)

 

 

필드 삭제하기

 

우리는 필드 타입이 여러개가 있고 이를 실습하기 위해 추가해준 average_score와 is_something 필드를 삭제해보려 합니다.

 

먼저 .exit을 입력해 SQLite3에서 장고 프로젝트로 돌아옵니다.

sqlite> .exit

(DjangoProjects) C:\Users\User\DjangoProjects\Scripts\mysite>

 

우리가 이번에 추가한 필드들을 삭제하겠다는 뜻은

 

polls/migrations에서

 

필드를 추가하며 모델을 수정한 0002_qeustion_average_score...에서

모델을 처음에 생성한 0001_initial.py로 돌아가겠다는 뜻과 같습니다.

(위에서 볼드체로 0002를 잘 기억해두라고 말씀드린 이유입니다.)

 

이렇게 이전의 상태(마이그레이션)로 돌아가는 명령어가 있습니다.

터미널에서

 

polls의 0001로 migrate합니다.

python manage.py migrate polls 0001
(DjangoProjects) C:\Users\User\DjangoProjects\Scripts\mysite>python manage.py migrate polls 0001
Operations to perform:
  Target specific migration: 0001_initial, from polls
Running migrations:
  Rendering model states... DONE
  Unapplying polls.0002_question_average_score_question_is_something... OK

 

Unapplying poll.0002 ~"~ 즉, polls 앱에서 필드들 average_score와 is_something을 적용했던 0002 마이그레이션의 적용을 취소했다고 뜹니다.

 

정말 그랬는지 확인해 보겠습니다.

 

 

 

다시 DB에 접속하고

(DjangoProjects) C:\Users\User\DjangoProjects\Scripts\mysite>sqlite3 db.sqlite3

 

 

polls앱의 question테이블의 스키마를 살펴보면

sqlite> .schema polls_question
CREATE TABLE IF NOT EXISTS "polls_question" 
    ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, 
    "question_text" varchar(200) NOT NULL, 
    "pub_date" datetime NOT NULL);

필드를 추가하기 전과 마찬가지로 id, question_text, pub_date만 있는 것을 볼 수 있습니다.

 

 

 

 

 

그런데!

 

이대로 두고 다음에 또 마이그레이션을 진행하면 average_score, is_something 필드가 추가된 상태로 만들어진 마이그레이션이 또 실행되어 테이블이 수정될 것입니다.

 

이를 방지하기 위해서는

 

 

 

생성된 마이그레이션 0002를 제거해줍니다.

 

 

 

그 다음 

 

 

polls/models.py에서 적어줬던 필드 추가 코드들도 삭제해줍니다.

 

그러면 터미널에서 마이그레이트를 진행해도

 

(DjangoProjects) C:\Users\User\DjangoProjects\Scripts\mysite>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  No migrations to apply.

 

더 이상 적용할 마이그레이션이 없다(모든 마이그레이션이 적용되었다)고 정상적으로 출력됩니다.