Join 쿼리 (MySQL) 한번만 수행되고 참조하는 테이블 정보는 캐쉬되어 해당 테이블의 데이터 값을 가져올 때 DB 쿼리 안함
one to one, foreignkey 정참조의 경우에 사용
select_related('필드명')
from django.db import models
class Menu(models.Model):
name = models.CharField(max_length = 50)
def __str__(self):
return self.name
class Meta:
db_table = 'menus'
class Category(models.Model):
name = models.CharField(max_length = 50)
menu = models.ForeignKey('Menu', on_delete = models.SET_NULL, null = True)
def __str__(self):
return self.name
class Meta:
db_table = 'categories'
👇 django shell 진입 👇
(project) $ ./manage.py shell
#categories 테이블에서 id가 1인 객체가 참조하고 있는 메뉴의 객체를 가져올 때
#select_related 사용하지 않고 데이터 가져올 시 hit 2번함
category = Category.objects.get(id=1)
category.menu
<Menu: drink>
#select_related 사용시 hit 한번만 함
category = Category.objects.select_related('menu').get(id=1)
category.menu
<Menu: drink>
별도의 2개의 쿼리를 수행 후에 파이썬에서 조인한다.
역참조시 related_name을 사용해야 한다.
many to many, foreignkey 역참조 관계에서도 사용 가능하다.
prefetch_related('related_name')
from django.db import models
class Menu(models.Model):
name = models.CharField(max_length = 50)
def __str__(self):
return self.name
class Meta:
db_table = 'menus'
class Category(models.Model):
name = models.CharField(max_length = 50)
menu = models.ForeignKey('Menu', on_delete = models.SET_NULL, null = True, related_name = 'category')
def __str__(self):
return self.name
class Meta:
db_table = 'categories'
👇 django shell 진입 👇
(project) $ ./manage.py shell
#menus 테이블에서 id가 1인 객체가 갖고 있는 category의 모든 데이터를 조회할 때
drink = Menu.objects.prefetch_related('category').get(id=1)
for category in drink.category.all():
print(category.name)
'cold brew'
'espresso'
class Drink(models.Model):
name = models.CharField(max_length = 50)
category = models.ForeignKey('Category', on_delete = models.SET_NULL, null = True)
allergy = models.ManyToManyField('Allergy', through = 'AllergyDrink')
def __str__(self):
return self.name
class Meta:
db_table = 'drinks'
class Allergy(models.Model):
name = models.CharField(max_length = 50)
def __str__(self):
return self.name
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 = 'allergies_drinks'
👇 django shell 진입 👇
(project) $ ./manage.py shell
#알러지가 우유인 모든 음료를 조회하고 싶을 때
#prefetch_related 사용하지 않을 때
allergy = Allergy.objects.get(name = 'milk')
allergy.drink_set.all()
<QuerySet [<Drink: cold brew>, <Drink: macchiato>]>
#prefetch_related 사용할 때
allergy_id = Allergy.objects.get(name = 'milk').id
drinks = Drink.objects.filter(allergydrink__allergy=allergy_id).prefetch_related('allergydrink_set__allergy')
for drink in drinks:
print(drink.name)
'cold brew'
'macchiato'
filter(allergydrink__allergy = allergy_id)
_set
은 쓰지 않는다.