app작업 진행하기
# models.py
from django.db import models
class Category(models.Model):
menu = models.ForeignKey('menu', on_delete=models.CASCADE)
name = models.CharField(max_length=40)
class Meta:
db_table = 'categories'
class Menu(models.Model):
name = models.CharField(max_length=40)
class Meta:
db_table = 'menu'
class Drink(models.Model):
category = models.ForeignKey('Category', on_delete=models.CASCADE)
korean_name = models.CharField(max_length=40)
english_name = models.CharField(max_length=40)
description = models.TextField()
class Meta:
db_table = 'drinks'
class Allergy_Drink(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 Allergy(models.Model):
name = models.CharField(max_length=40, default="")
drink_set = models.ManyToManyField(Drink, through=Allergy_Drink)
class Meta:
db_table = 'allergy'
class Nutrition(models.Model):
one_serving_kca = models.DecimalField(max_digits=10, decimal_places=2, null=True)
sodium_mg = models.DecimalField(max_digits=10, decimal_places=2, null=True)
saturated_fat_g = models.DecimalField(max_digits=10, decimal_places=2, null=True)
sugars_g = models.DecimalField(max_digits=10, decimal_places=2, null=True)
protein_g = models.DecimalField(max_digits=10, decimal_places=2, null=True)
caffeine_mg = models.DecimalField(max_digits=10, decimal_places=2, null=True)
drink = models.ForeignKey('Drink', on_delete=models.CASCADE, null=True)
size = models.ForeignKey('Size', on_delete=models.CASCADE, null=True)
class Meta:
db_table = 'nutritions'
class Image(models.Model):
image_url = models.CharField(max_length=1000)
drink = models.ForeignKey('Drink', on_delete=models.CASCADE)
class Meta:
db_table = 'images'
class Size(models.Model):
name = models.CharField(max_length=40)
size_ml = models.CharField(max_length=40, null=True)
size_fluid_ounce = models.CharField(max_length=40, null=True)
class Meta:
db_table = 'sizes'
select_related()
없이 바로 관계를 맺은 객체 정보를 볼 수 있다.
select_related()
를 사용하는 이유 : Hit(datebase에 query를 요청하는 횟수)를 최소화하여 성능을 높인다.select_related()
는 JOIN을 사용하여 foreign-key로정참조
할 때 사용하며 QuerySet을 가져올 때, 미리 related objects까지 불러오는 함수이다.
-> 비록 쿼리는 복잡해지지만 불러온 data들은 데이터베이스 서버가 종료되기 전까지 cache에 남게되어 매 쿼리마다 DB에 접근하지 않아도 된다.
prefetch_related()
:select_related()
와 같이 data를 cache에 저장하며, 모든 relationships에서 사용이 가능하다.
->select_related()
은 하나의 Query로 related Objects들을 불러오지만,Prefetch_related()
는 main Query가 실행이 된 후 별도의 Query가 실행이 된다. 따라서 리소스 소모가 더 크다.
>>> from products.models import Category, Menu, Drink, Nutrition, Image, Allergy_Drink, Allergy, Size
# 정참조
>>> a = Drink.objects.get(pk=1)
>>> a.category.name
'콜드 브루'
# select_related를 사용한 경우
>>> a = Drink.objects.select_related('category').get(pk=1)
>>> a.category.name
'콜드 브루'
>>> Drink.objects.select_related('category').get(pk=1).category.name
'콜드 브루'
# prefetch_related를 사용한 경우
>>> Drink.objects.prefetch_related('category').get(id=1).category.name
'콜드 브루'
# 역참조
>>> a = Category.objects.get(id=1)
>>> b = a.drink_set.all()
>>> b
<QuerySet [<Drink: Drink object (1)>, <Drink: Drink object (2)>]>
>>> b[0].korean_name
'나이트로 바닐라 크림'
# prefetch_related()를 사용한 경우
>>> a=Category.objects.prefetch_related('drink_set').get(id=1)
>>> b=a.drink_set.all()
>>> b
<QuerySet [<Drink: Drink object (1)>, <Drink: Drink object (2)>]>
>>> b[0].korean_name
'나이트로 바닐라 크림'
>>> Category.objects.prefetch_related('drink_set').get(id=1).drink_set.values()
<QuerySet [{'id': 1, 'category_id': 1, 'korean_name': '나이트로 바닐라 크림', 'english_name': 'Nitro Vanilla Cream',
'description': '부드러운 목넘김의 나이트로 커피와 바닐라 크림의 매력을 한번에 느껴보세요!'},
{'id': 2, 'category_id': 1, 'korean_name': '나이트로 콜드 브루', 'english_name': 'Nitro Cold Brew',
'description': '나이트로 커피 정통의 캐스케이딩과 부드러운 콜드 크레마! 부드러운 목 넘김과 완벽한 밸런스에 커피 본연의 단맛을 경험할 수 있습니다.'}]>
# many-to-many 관계 역참조
>>> Allergy.objects.get(id=1).drink_set.values()
<QuerySet [{'id': 5, 'category_id': 4, 'korean_name': '트리플 미니 스콘', 'english_name': 'Triple Mini Scone',
'description': '헤이즐넛 초콜릿, 치즈, 크랜베리 세 가지 맛의 스콘이 각각 들어있는 미니 사이즈의 스콘입니다.'},
{'id': 8, 'category_id': 5, 'korean_name': '티라미수 타르트', 'english_name': 'Tiramisu Tart',
'description': '촉촉한 초콜릿 브라우니 타르트 위에 달콤한 밀크 가나슈를 넣은 마스카포네 크림 무스를 올린 티라미수 타르트입 니다.'}]>
# prefetch_related()를 사용하여 many-to-many 관계를 대상으로 참조할때 data를 참조 대상까지 cache에 저장한다.
>>> Allergy.objects.prefetch_related('drink_set').get(id=1).drink_set.values()
<QuerySet [{'id': 5, 'category_id': 4, 'korean_name': '트리플 미니 스콘', 'english_name': 'Triple Mini Scone',
'description': '헤이즐넛 초콜릿, 치즈, 크랜베리 세 가지 맛의 스콘이 각각 들어있는 미니 사이즈의 스콘입니다.'},
{'id': 8, 'category_id': 5, 'korean_name': '티라미수 타르트', 'english_name': 'Tiramisu Tart',
'description': '촉촉한 초콜릿 브라우니 타르트 위에 달콤한 밀크 가나슈를 넣은 마스카포네 크림 무스를 올린 티라미수 타르트입니다.'}]>
# allergy, drink는 각자의 테이블에서 생성한 객체를 넣어준 변수이다.
>>> connect = Allergy_Drink(allergy_id = allergy, drink_id = drink)
>>> connect.save()
>>> Allergy_Drink.objects.create(allergy_id=1, drink_id=1)
>>> a = Drink.objects.create(id=9, category_id=1, korean_name="아이스 아메리카노", english_name="ice americano", description="아이스 아메리카노")
>>> a.save()
>>> b = Allergy.objects.create(name="사과")
>>> b.save()
>>> a.allergy_set.add(b)
# b.drink_set.add(a)도 가능
# allergy_drink 테이블에 allergy_id=7(사과), drink_id=9 row가 추가됨