이번에는 토대로 직접 westarbucks 모델을 작성해보도록 하자. (스타벅스 홈페이지 참고)
일단 westarbucks 프로젝트를 만들고 products라는 앱을 추가한다. 이후 다음과 같이 모델링을 해주었다.
from django.db import models
# Create your models here.
class Menu(models.Model):
name = models.CharField(max_length=45)
class Meta:
db_table = 'menu'
class Category(models.Model):
menu = models.ForeignKey(Menu, on_delete=models.CASCADE, null=True)
name = models.CharField(max_length=45)
class Meta:
db_table = 'categories'
class Drink(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
korean_name = models.CharField(max_length=45)
english_name = models.CharField(max_length=45)
description = models.TextField()
class Meta:
db_table = 'drinks'
class Image(models.Model):
drink = models.ForeignKey(Drink, on_delete=models.CASCADE)
image_url = models.CharField(max_length=2000)
class Meta:
db_table = 'images'
class Allergy(models.Model):
name = models.CharField(max_length=45)
allergy_drink = models.ManyToManyField(Drink, through='AllergyDrink')
class Meta:
db_table = 'allergies'
class AllergyDrink(models.Model):
allergy= models.ForeignKey(Allergy, on_delete=models.CASCADE)
drink = models.ForeignKey(Drink, on_delete=models.CASCADE)
class Meta:
db_table = 'allergy_drink'
class Size(models.Model):
name = models.CharField(max_length=45)
size_ml = models.CharField(max_length=45)
size_fluid_ounce = models.CharField(max_length=45)
class Meta:
db_table = 'sizes'
class Nutrition(models.Model):
drink = models.OneToOneField(Drink, on_delete=models.CASCADE)
size = models.ForeignKey(Size, on_delete=models.CASCADE)
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 = 'nutritions'
위의 내용을 대략 설명하자면 우선 테이블은 Menu, Category, Drink, Image, Allergy, Size, Nutrition이 있다.
일대다 관계는 클래스 내의 ForeignKey를 보면 알 수 있으며 관계를 맺을 모델의 객체와 on_detete를 인자로 받는다. 아직 정의되지 않은 모델의 경우 객체 대신 모델명으로 대체를 해주어도 된다. (모델 객체를 쓰려면 해당 모델이 먼저 정의되어야 함.)
예시) menu = models.ForeignKeyField('Menu', on_delete = models.CASCADE)
ForienKey의 on_delete은 참조된 객체가 삭제됐을 경우 참조하는 row에 대한 동작을 결정한다.
Allergy 테이블을 보면 ManyToManyField를 볼 수 있는데, 이는 다대다 관계를 표현하기 위함으로 관계를 맺고 있는 테이블 중 어떤 곳에 추가해도 상관없다. 또한 다대다 관계를 표현하기 위해 각 테이블의 pk를 외래키로 갖는 AllergyDrink 모델을 만들어 주었다.
실수 고정소수점을 나타내는 타입이다. max_digit
은 소수부를 포함한 전체 실수 총 자릿수를 정하며, decimal_places
는 소수부의 자릿수를 결정한다.
> python manage.py makemigrations produtcs
> pyhton manage.py migrate
mysql에서 데이터베이스를 확인해보면 방금 구현한대로 잘 만들어진 것을 확인할 수 있다.
# 데이터 생성
Menu.objects.create(name='음료')
Menu.objects.create(name='푸드')
#
# 데이터 삭제
Menu.objects.filter(pk=6).delete()
# 데이터 생성
nitro = Drink.objects.get(pk=1)
s = Size.objects.get(pk=1)
Nutrition.objects.create(one_serving_kcal=80, sodium_mg=40, saturated_fat_g=2,
...: sugars_g=10, protein_g=1, caffeine_mg=232, drink=nitro, size=s)
# 데이터 생성
m = Menu.objects.get(pk=1)
m.category_set.create(name='콜드 브루')
m.category_set.create(name='에스프레소')
# 또는
m = Menu.objects.get(pk=1)
c = Category(menu = m, name='콜드 브루')
c.save()
# 데이터 삭제
# 데이터 생성
a = Allergy.objects.get(pk=1)
d = Drink.objects.get(pk=1)
ad = AllergyDrink(allergy = a, drink = b)
ad.save()
# 또는
milk = Allergy.objects.get(pk=1)
bean = Allergy.objects.get(pk=2)
malt = Drink.objects.get(pk=4)
malt.allergy_set.add(milk, bean)
# 데이터 삭제
AllergyDrink.objects.filter(drink_id=4).delete()
# 또는
malt.allergy_set.remove(bean)
오늘 배운점은 다음과 같다.
첫째, 다대다 관계 표현법. 다대다 관계를 표현할 때는 ManyToManyField
를 사용하여 정의할 수 있다.
둘째, add(). 다대다 관계에서는 add()
를 이용하여 관계를 맵핑시킬 수 있다. 정의되어있는 중간 테이블에 각 테이블의 외래키가 자동으로 입력된다.
셋째. 역참조 관계. 이전 까지 ForeignKeyField
로 관계를 표현하는 것과 OneToManyField
, ManyToManyField
등으로 관계를 표현하는 것의 차이를 몰랐었는데, 역참조 관계라는 것을 알게되고 그 차이를 알 수 있게 되었다. 관계를 나타내는 OneToManyField
같은 클래스는 하나의 객체를 반환하기 때문에 역참조를 할 시 _set
를 통하지 않고도 참조가 가능하고, ForeignKeyField
는 QuerySet
을 반환하기 때문에 역참조 시 _set
을 써야한다. 해당 내용은 세번째 참고링크를 더 볼 것.
참고:
Related objects reference
Many-to-many relationships
⭐️[Django] OneToOne 모델 이해하기