[TIL/Django] C.R.U.D 1 (westarbuck 모델 작성)

나른한 개발자·2022년 1월 10일
0

studylog

목록 보기
24/45
post-custom-banner

이번에는 토대로 직접 westarbucks 모델을 작성해보도록 하자. (스타벅스 홈페이지 참고)

일단 westarbucks 프로젝트를 만들고 products라는 앱을 추가한다. 이후 다음과 같이 모델링을 해주었다.

1. models.py 작성

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이 있다.

One-to-many

일대다 관계는 클래스 내의 ForeignKey를 보면 알 수 있으며 관계를 맺을 모델의 객체와 on_detete를 인자로 받는다. 아직 정의되지 않은 모델의 경우 객체 대신 모델명으로 대체를 해주어도 된다. (모델 객체를 쓰려면 해당 모델이 먼저 정의되어야 함.)
예시) menu = models.ForeignKeyField('Menu', on_delete = models.CASCADE)

on_delete

ForienKey의 on_delete은 참조된 객체가 삭제됐을 경우 참조하는 row에 대한 동작을 결정한다.

  • CASCADE: 참조하는 ForeingKeyField 값도 함께 삭제한다.
  • PROTECT: ProtectedError를 발생시켜 참조되고 있는 요소가 삭제되지 않도록 한다.
  • SET_NULL: ForeinKeyField 값을 NULL로 설정한다.
  • SET_DEFAULT: ForeinKeyField 값을 Default 값으로 설정한다.
  • SET(): SET() 함수로 넘어온 값으로 설정한다.
  • DO_NOTHING: 아무것도 하지 않음.(참조 무결성을 해칠 위험이 있으므로 권장하지 않는다)

ManyToManyField

Allergy 테이블을 보면 ManyToManyField를 볼 수 있는데, 이는 다대다 관계를 표현하기 위함으로 관계를 맺고 있는 테이블 중 어떤 곳에 추가해도 상관없다. 또한 다대다 관계를 표현하기 위해 각 테이블의 pk를 외래키로 갖는 AllergyDrink 모델을 만들어 주었다.

DecimalField

실수 고정소수점을 나타내는 타입이다. max_digit은 소수부를 포함한 전체 실수 총 자릿수를 정하며, decimal_places는 소수부의 자릿수를 결정한다.

2. Migrate 및 데이터베이스 확인

> python manage.py makemigrations produtcs
> pyhton manage.py migrate

mysql에서 데이터베이스를 확인해보면 방금 구현한대로 잘 만들어진 것을 확인할 수 있다.

3. QuerySet API 이용하여 데이터 다뤄보기

데이터 다루기

# 데이터 생성
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를 통하지 않고도 참조가 가능하고, ForeignKeyFieldQuerySet을 반환하기 때문에 역참조 시 _set을 써야한다. 해당 내용은 세번째 참고링크를 더 볼 것.


참고:
Related objects reference
Many-to-many relationships
⭐️[Django] OneToOne 모델 이해하기

profile
Start fast to fail fast
post-custom-banner

0개의 댓글