장고 내에 app을 만들면 models.py, views.py 등이 들어있는 app 폴더가 생긴다.
Web 2.0 기준이라면 이 app을 기능마다 만들겠지만 3.0은 entity를 기준으로 한다. 데이터의 성격을 보고 이게 상품 관련인지, 사용자에 관련된 건지에 따라서 묶인 단위가 entity이다.
models.py에 쓰는 class는 곧 DB의 table이다.
class 안에 <column명> = models.<field method> 형태로 column을 넣는다.
field로 줄 수 있는 것들 중 하나가 ForeignKey인데, column명으로 준 거에 장고가 자동으로 _id를 붙인다. 그리고 참조할 테이블의 class와 참조했던 게 사라졌을 때 어떻게 처리할 건지를 attribute로 줘야 된다. 참조할 테이블의 class명은 따옴표를 붙여 string으로 주는 게 좋다. 따옴표 없이 그냥 쓰면 class 선언 순서에 영향을 받는다. string으로 주면 코드를 다 읽고 나서 메모리 상에서 일치하는 걸 맵핑한다.
참조했던 게 사라지면 이 테이블에 있는 연관 데이터도 삭제 -> on_delete=models.CASCADE
참조했던 게 사라지면 이 테이블에서 해당 값을 null로 변경 -> on_delete=models.SET_NULL, null=True
null을 허용하지 않는게 DB의 기본 성질이라 null을 넣으려면 null=True로 허용해줘야 된다.
one to one -> models.OneToOneField(<참조할 테이블의 class명>, on_delete=<옵션>)
many to many -> 중간 테이블 class를 만들어서 거기에 두개 테이블을 참조하는 foreign key 2개를 만든다.
이대로 만들면 테이블의 이름이 <app 이름>_<class 이름> 이렇게 영어 소문자로 된다.
테이블명을 지정하려면 각 class 안에 아래와 같은 코드를 넣어줘야 된다.
class Meta:
db_table = '<테이블명>'
스타벅스 데이터 모델링했던 걸 기반으로 만든 models.py는 아래와 같다.
from django.db import models
from django.db.models.deletion import CASCADE
class Menu(models.Model):
name = models.CharField(max_length=5)
class Meta:
db_table = 'menus'
class Category(models.Model):
name = models.CharField(max_length=10)
menu = models.ForeignKey('Menu', on_delete=models.CASCADE)
class Meta:
db_table = 'categories'
class Drink(models.Model):
name = models.CharField(max_length=20)
category = models.ForeignKey('Category', on_delete=models.CASCADE)
english_name = models.CharField(max_length=50)
description = models.CharField(max_length=100, null=True)
is_new = models.BooleanField()
class Meta:
db_table = 'drinks'
class Image(models.Model):
url = models.CharField(max_length=1000)
drink = models.ForeignKey('Drink', on_delete=models.CASCADE)
class Meta:
db_table = 'images'
class Nutrition(models.Model):
drink = models.ForeignKey('Drink', on_delete=models.CASCADE)
calories = models.CharField(max_length=10)
saturated_fat = models.CharField(max_length=10)
protein = models.CharField(max_length=10)
sodium = models.CharField(max_length=10)
total_carbs = models.CharField(max_length=10)
caffeine = models.CharField(max_length=10)
class Meta:
db_table = 'nutritions'
class Allergy(models.Model):
allergen = models.CharField(max_length=10)
class Meta:
db_table = 'allergies'
class DrinkAllergy(models.Model):
drink = models.ForeignKey('Drink', on_delete=models.CASCADE)
allergy = models.ForeignKey('Allergy', on_delete=models.DO_NOTHING)
class Meta:
db_table = 'drinks_allergies'
models.py를 저장하고 나서
makemigrations 해서 변경 사항을 확인 한 뒤 migration 파일을 만들고
migrate하면 migration 파일을 DB에 반영한다.
명령을 실행할 때 뒤에 app명을 붙이면 해당 app에 대해서만 실행한다. 아무것도 주지 않으면 INSTALLED_APPS 전부를 훑는다.
migrate 할 때 특정 마이그레이션 파일만 지정해 그것만 적용할 수도 있다.
$ python manage.py makemigrations # 마이그레이션 파일 만들기
$ python manage.py showmigrations # 마이그레이션 파일, 반영 상태 확인
$ python manage.py migrate # 마이그레이션 파일 반영
$ python manage.py sqlmigrate <app명> <마이그레이션 파일 번호> # raw query로는 어떻게 보이는지 알려줌
반영된 migration 상태와 mysql에 있는 걸 일치시키는 게 중요하다. dbshell에서는 직접 건드리지 말고,
$ python manage.py shell
이 장고 쉘에서 CRUD 하는 편이 안전하다. 마이그레이션 파일을 함부로 편집하거나 삭제하면 에러가 더 생길 수도 있다. 만일 migration을 초기화할 일이 생긴다면 혹시 모를 상황에 대비해 DB를 백업해두고, 참고 링크를 보며 조심스레 접근하자.
DB를 확인하려면,
$ python manage.py dbshell
또는 mysql에 로그인한다.
$ mysql -u root -p # 로그인
mysql > show databases;
mysql > use <DB명>;
'Django' 카테고리의 다른 글
백엔드 서버 되어보기 (0) | 2021.02.06 |
---|---|
Django 회원가입, 로그인 엔드포인트 (0) | 2021.01.30 |
django.db.utils.OperationalError: (1054, "Unknown column 'menu_id_id' in 'categories'") (0) | 2021.01.28 |
Django CRUD - QuerySet API (0) | 2021.01.27 |
Django - mysql 설치, settings.py 설정 (0) | 2021.01.25 |