스타벅스 음료 카테고리 데이터베이스 짜기
위의 데이터베이스를 django로 모델링하기
app이름은 starbucks로 만들었음
from django.db import models
class Menu(models.Model):
menu_name=models.CharField(max_length=45)
class Category(models.Model):
menu=models.ForeignKey(Menu, on_delete=models.CASCADE)
category_name=models.CharField(max_length=45)
class NutritionInformation(models.Model):
one_serving_kcal=models.DecimalField(max_digits=10,decimal_places=2)
sodium_mg=models.DecimalField(max_digits=10,decimal_places=2)
saturated_fat_g=models.DecimalField(max_digits=10,decimal_places=2)
sugars_g=models.DecimalField(max_digits=10,decimal_places=2)
protein_g=models.DecimalField(max_digits=10,decimal_places=2)
caffeine_mg=models.DecimalField(max_digits=10,decimal_places=2)
class Drink(models.Model):
category=models.ForeignKey(Category, on_delete=models.CASCADE)
drink_name=models.CharField(max_length=45)
nutrition=models.ForeignKey(NutritionInformation, on_delete=models.CASCADE)
class Size(models.Model):
nutrition=models.ForeignKey(NutritionInformation, on_delete=models.CASCADE)
size_name=models.CharField(max_length=45)
size_ml=models.IntegerField(max_length=30)
size_fluid_ounce=models.IntegerField(max_length=30)
class Image(models.Model):
drink=models.ForeignKey(Drink, on_delete=models.CASCADE)
image_url=models.CharField(max_length=2000)
class Description(models.Model):
drink=models.ForeignKey(Drink, on_delete=models.CASCADE)
description=models.CharField(max_length=1000)
class Allergy(models.Model):
allergy_ingredient=models.CharField(max_length=45)
class AllergyDrink(models.Model):
allergy=models.ForeignKey(Allergy, on_delete=models.CASCADE)
drink=models.ForeignKey(Drink, on_delete=models.CASCA
해줘야 할 것
모델링한 클래스 아래에
class Meta:
db_table = "table_name"
추가해주기
이 때 테이블 명은 복수로
ForeignKey(class명 또는 스트링명, on_delete)
위와 같이 사용하는데 class명을 쓸 때 class명 또는 'class명'으로 사용
차이는? class명만 사용할 때는 이미 위에서 선언된 class명
'class명' 사용은 아직 선언되지 않았지만 언젠가는 선언될 class명 때 사용함
그냥 'class명'으로 쓰는게 마음이 편함
예시 1) class명 사용할 때
nutrition=models.ForeignKey(NutritionInformation, on_delete=models.SET_NULL,null=True)
예시 2) 'class명' 사용할 때
nutrition=models.ForeignKey('NutritionInformation', on_delete=models.SET_NULL,null=True)
참조하고 있는 요소가 삭제되었을 때 어떻게 처리할지
참조하고 있는 요소가 삭제되었을 때 (상위 존재가 삭제되었을 때) 하위 데이터 전부 지우기
ex) 만약 category에 콜드브루가 지워지면, 콜드브루를 참조하고 있던 음료들이 모두 지워짐
참조하고 있는 요소가 삭제되었을 때 참조하고 있는 데이터 부분만 null로 처리
데이터가 다 지워지지 않아서 데이터가 보호됨 필요없는 데이터가 아닌 이상 보통 SET_NULL사용
이때 null=True를 지정해주어야함 (기본값이 null=False기 때문에)
ForeignKey --> one to many 의미
OneToOneField --> one to one 의미
ManyToManyField --> Many to Many 의미
ManyToMany 필드 사용할 때 그냥 사용하면 장고가 중간 데이터 필드를 처리함
이 경우는 내가 중간 데이터 등을 컨트롤하기 힘듬
중간 테이블을 만들어서 사용하는 것이 컨트롤하기 좋음 --> 따라서 중간 테이블 만들기
중간 테이블 만들고 바로 중간 테이블 연결해주려면 throgh사용하기
사용 예시는 아래의 class Drink에서 확인하기
from django.db import models
class Menu(models.Model):
menu_name=models.CharField(max_length=45)
class Meta:
db_table = 'menus'
class Category(models.Model):
menu=models.ForeignKey('Menu', on_delete=models.SET_NULL, null=True)
category_name=models.CharField(max_length=45)
class Meta:
db_table = 'categories'
class NutritionInformation(models.Model):
one_serving_kcal=models.DecimalField(max_digits=10,decimal_places=2)
sodium_mg=models.DecimalField(max_digits=10,decimal_places=2)
saturated_fat_g=models.DecimalField(max_digits=10,decimal_places=2)
sugars_g=models.DecimalField(max_digits=10,decimal_places=2)
protein_g=models.DecimalField(max_digits=10,decimal_places=2)
caffeine_mg=models.DecimalField(max_digits=10,decimal_places=2)
class Meta:
db_table = 'nutritoninformations'
class Drink(models.Model):
category=models.ForeignKey('Category', on_delete=models.SET_NULL, null=True)
drink_name=models.CharField(max_length=45)
nutrition=models.OneToOneField('NutritionInformation', on_delete=SET_NULL, null=True)
menu=models.ForeignKey('Menu', on_delete=models.SET_NULL, null=True)
allergydrink=models.ManyToManyField('Allergy', through='AllergyDrink')
# Drink에서 바로 알러지 참조가 가능
# 중간 테이블 필요
# 중간 테이블 through='AllergyDrink' --> AllergyDrink에서 하는 일을 여기서 하겠다는 의미 / 중간 테이블 만들면 테이블 관리 편함
# through를 사용하지 않으면 장고에서 임의로 테이블 만들어서 사용 --> 이 경우는 중간 테이블 관리 어려움
class Meta:
db_table = 'drinks'
class Size(models.Model):
nutrition=models.ForeignKey('NutritionInformation', on_delete=models.SET_NULL,null=True)
size_name=models.CharField(max_length=45)
size_ml=models.IntegerField(default=0)
size_fluid_ounce=models.IntegerField(default=0)
# defualt=0은 초기값
class Meta:
db_table = 'sizes'
class Image(models.Model):
drink=models.ForeignKey('Drink', on_delete=models.SET_NULL, null=True
image_url=models.URLField(max_length=2000)
class Meta:
db_table='images'
class Description(models.Model):
drink=models.ForeignKey('Drink', on_delete=models.SET_NULL, null=True)
description=models.CharField(max_length=1000)
class Meta :
db_table='descriptions'
class Allergy(models.Model):
allergy_ingredient=models.CharField(max_length=45)
class Meta:
db_table = 'allergies'
# AllergyDrink --> 중간테이블
class AllergyDrink(models.Model):
allergy=models.ForeignKey('Allergy', on_delete=models.SET_NULL, null=True)
drink=models.ForeignKey('Drink', on_delete=models.SET_NULL, null=True)
class Meta:
db_table = 'allergydrinks'
위의 내용을 migration하고 shell에서 확인해보기
Category.objects.create(category_name='콜드 브루 커피', menu_id=1)
위의 예시 menu_id=1 와 같이 id를 배정해줌
menu_id에서 menu는 class내의 데이터이름
menu_id가 class Category에 데이터베이스 필드명
(class명 Menu의 id=1이 아니라 Category class의 menu라는 데이터 / 여기서 menu데이터는 Menu class와 Foreignkey로 연결되어있음 )
drink table에 allergydrink (ManyToMany로 연결되어있음) 를 추가하려면 일반적인 방법처럼 추가할 수 없음
allergydrink 테이블에 allergy의 id와 drink의 id를 입력해주어야함
drink 테이블에 객체로 전달해주는 방법
이 방법이 좀 더 편리함 (데이터가 많아질수록 편리함)
아래의 예시와 같이 데이터 추가할 수 있음
예시)
drink = Drink.objects.get(id=1)
drink.allergydrink.add(Allergy.objects.get(id=2))
drink안의 allergydrink 불러와서 여기에 Allergy.objects.get(id=2)라는 객체를 추가해주는 형식 (allergies 테이블에 데이터 미리 추가되어있어야함)
여기서 drink는 id=1로 확정된 상태, 알레르기의 id=2의 데이터를 가지고와서 이 데이터를 추가해주는 느낌
여러개의 알레르기를 입력하고 싶을 때
여러개의 알레르기를 입력하고 싶을 때는 아래와 같이 입력
drink = Drink.objects.get(id=1)
drink.allergydrink.add(Allergy.objects.get(id=2))
drink.allergydrink.add(Allergy.objects.get(id=3))