마이그레이션을 통한 데이터베이스 스키마 관리

2022. 1. 4. 16:07강의 정리/Django Models

반응형

↑관계형 데이터베이스 (mariaDB)에 대해서 자세히 알고싶다면???

https://blog.naver.com/yardyard/222555167886

 

MySQL(MariaDB) 18~21 인터넷과 데이터베이스

출처 : https://youtu.be/hjgaxlTQMXk 오류 참조 : https://hoon93.tistory.com/9 https://languagesto...

blog.naver.com

 

-MYSQL에서 DATABASE를 표현하는 다른 말로, 스키마라는 표현을 사용함.

 

 


 

Migrations란?

모델변경내역을 "데이터베이스 스키마"로 반영시키는 효율적인 방법을 제공 

# Migrations을 통해서 우리는 모델만 개발하고 데이터베이스에 자동으로 반영시킬 수 있다.

 

관련 명령

  • 마이그레이션 파일 생성 # 순서 1
>>> python manage.py makemigrations <앱이름>
  • 지정 데이터베이스에 마이그레이션 적용 # 순서 3
>>> python manage.py migrate <앱이름>
  • 마이그레이션 적용 현황 출력 # 중간 중간 틈틈히
>>> python manage.py showmigrations <앱이름>

출력된 코드

C:\Users\yardy\Desktop\DjangoPractice\dongbaek>python manage.py showmigrations
accounts
 [X] 0001_initial
 [X] 0002_alter_profile_user
admin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
 [X] 0003_logentry_add_action_flag_choices
auth
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0009_alter_user_last_name_max_length
 [X] 0010_alter_group_name_max_length
 [X] 0011_update_proxy_permissions
 [X] 0012_alter_user_first_name_max_length
church
 (no migrations)
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
inflearn
 [X] 0001_initial
instagram
 [X] 0001_initial
 [X] 0002_post_is_public
 [X] 0003_post_photo
 [X] 0004_auto_20211231_1531
 [X] 0005_auto_20211231_1722
 [X] 0006_auto_20220103_1516
sessions
 [X] 0001_initial
  • 지정 마이그레이션의 SQL 내역 출력 # 순서 2
>>> python manage.py sqlmigrate <앱이름> <마이그레이션-이름>
  • 장고의 전체 기본 앱들에 대해서 마이그레이션 수행
>>>python manage.py migrate

 

 

 


 

Migrations 파일

데이터베이스에 어떤 변화를 가하는 Operation들을 나열

  • 기본 Operation : 테이블 생성 / 삭제, 필드 추가 / 삭제 등
  • 커스텀 Operation : 파이썬 / SQL Operation # ex)데이터 마이그레이션 등 Migration에 커스텀 과정을 넣을 수 있다.

 

대개 모델로부터 자동 생성 -> makemigrations 명령

  • 모델 참조없이 빈 마이그레이션 파일 만들어서 직접 채워넣기도 함.

 

주의) 같은 Migration 파일이라 할지라도, DB종류에 따라 다른 SQL이 생성됩니다.

  • 모든 데이터베이스 엔진들이 같은 기능을 제공하지는 않는다.
  • ex) SQLite DB에서는 기존 테이블에 컬럼 추가가 지원되지 않음.

 

ex) dongbaek/accounts/migrations/0001_initial.py

# Generated by Django 3.2.10 on 2022-01-03 04:50

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    initial = True

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
    ]

    operations = [
        migrations.CreateModel(
            name='Profile',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('address', models.CharField(max_length=100)),
                ('zipcode', models.CharField(max_length=6)),
                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
            ],
        ),
    ]

 


 

Migrations 파일 생성 및 적용 과정

 

0. 앱/models.py

  • 모델 변경 # makemigrations 명령

1. 마이그레이션 파일들 생성

  • 필히, 생성된 마이그레이션 파일 내역 확인 + sqlmigrate 명령으로 SQL 확인
  • 즉 나의 의도에 맞게 생성이 되었는지 확인

2. 데이터베이스 서버

  • migrate 명령으로 DB에 적용

 

 


 

언제 makemigrations를 하는 가?

모델 필드 관련된 어떠한 변경이라도 발생 시에 마이그레이션 파일 생성

  • 실제로 DB Shceme에 가해지는 변화가 없더라도 수행

 

마이그레이션 파일은 모델의 변경내역을 누적하는 역할

  • 적용된 마이그레이션 파일은 절대 삭제하면 안됨
  • 마이그레이션 파일이 너무 많아질 경우, squashmigrations 명령으로 다수의 마이그레이션 파일을 통합할 수 있다.

 

 


 

마이그레이션 Migrate ( 정 / 역 방향 )

정방향 (1->2->3->4->5)

역방향(5->4->3->2->1)

 

python manage.py migrate <앱이름>

  • 미적용 <마이그레이션-파일>부터 <최근-마이그레이션-파일>까지 정방향으로 순차적으로 수행

 

python manage.py migrate <앱이름> <마이그레이션-이름>

  • 지정된 <마이그레이션-이름>이 현재 적용된 마이그레이션보다
  • 이후라면, 정방향으로 순차적으로 지정된 마이그레이션까지 정방향 수행
  • 이전이라면, 역방향으로 순차적으로 지정 마이그레이션 이전까지 역방향 수행

 

즉 현재의 migration 위치를 파악하는게 중요~!!!! # showmigrations 명령

ex) 1~7번까지의 migration 파일이 있을 때 현재가 5번 파일인데 3번 파일을 지정하면 5번 취소, 4번 취소, 하여 역방향으로 3번으로 가게 됨

 

코드로 설명하면

>>> python manage.py migrate <app> 0003_a.py

0007_a.py

0006_a.py

0005_a.py (현재 위치) ↓ 지정된 위치로 역방향 이동

0004_a.py                 

0003_a.py (지정된 위치)

0002_a.py

0001_a.py

 

 

 

ex) 정방향 예시로 아래 코드를 예로 들면

>>> python manage.py migrate <app> 0005_a.py

0007_a.py

0006_a.py

0005_a.py (지정된 위치)  지정된 위치로 정방향 이동

0004_a.py               

0003_a.py (현재 위치) ↑

0002_a.py

0001_a.py

 

 

 


 

마이그레이션 이름 지정

전체 이름(파일명)을 지정하지 않더라도, 1개를 판별할 수 있는 일부만 지정해도 OK

 

migrations/000_1_initial.py
migrations/000_2_created_field.py
migrations/000_2_update_field.py

Shell
>>> python manage.py migrate blog 000 # FAIL 3개 파일에 매칭
>>> python manage.py migrate blog 100 # FAIL 매칭되는 파일이 없음
>>> python manage.py migrate blog 0001 # OK
>>> python manage.py migrate blog 0002 # FAIL 2개 파일에 매칭
>>> python manage.py migrate blog 0002_c # OK
>>> python manage.py migrate blog 0002_create # OK
>>> python manage.py migrate blog 0002_update # OK
>>> python manage.py migrate blog zero # 앱의 모든 마이그레이션을 rollback

 

 


 

 

새로운 필드가 필수필드라면?

필수필드 여부 : blank / null 옵션이 모두 False 일 때 (디폴트)

 

makemigrations 명령을 수행할 때, 기존 Record들에 어떤 값을 채워넣을 지 묻습니다.

  1. 지금 그 값을 입력하겠다. # 반드시 필드 타입에 맞게 값을 채워넣어야 한다.
  2. 명령 수행을 중단
C:\Users\yardy\Desktop\DjangoPractice\dongbaek>python manage.py makemigrations inflearn
You are trying to add a non-nullable field 'author' to post without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py


Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now       
Type 'exit' to exit this prompt
>>> 1
Migrations for 'inflearn':
  inflearn\migrations\0002_post_author.py
    - Add field author to post

 

# dongbaek/inflearn/models.py

from django.conf import settings
from django.db import models
from django.conf import settings

from django.db.models.deletion import CASCADE
# Create your models here.

class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE, related_name="inflearn_author_set")
    title = models.CharField(max_length=100)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now_add=True)

 


 

협업 Tip

절대 하지 말아야 할 일

  • 팀원 각자가 마이그레이션 파일을 생성 -> 충돌 발생

 

추천 ) 마이그레이션 파일 생성은 1명이 전담해서 생성

  • 생성한 마이그레이션 파일을 버전관리에 넣고, 다른 팀원들은 이를 받아서 migrate만 수행

 

개발 시에 "서버에 아직 반영하지 않은" 마이그레이션을 다수 생성했었다면?

  • 이를 그래도 서버에 반영 ( migrate ) 하지말고,
  • 하나의 마이그레이션으로 합쳐서 적용하기를 권장

방법 1) 서버로의 미적용 마이그레이션들을 모두 롤백 -> 롤백된 마이그레이션들을 모두 제거 -> 새로이 마이그레이션 파일 생성

 

방법 2) 미적용 마이그레이션들을 하나로 합치기 -> squashmigrations 명령

 

 

반응형