Django

django | prefetch_related()

JOOHUUN 2022. 8. 13. 19:21

구하려는 객체가 정참조 multiple objects(many-to-many or one-to-many)이거나, 또는 역참조 Foreign Key일때 사용한다.

# Create your models here.

from django.db import models

class Topping(models.Model):
    name = models.CharField(max_length=30)

class Pizza(models.Model):
    name = models.CharField(max_length=50)
    toppings = models.ManyToManyField(Topping)

    def __str__(self):
        return "%s (%s)" % (
            self.name,
            ", ".join(topping.name for topping in self.toppings.all()),
        )

1. 장고셸을 사용해서 데이터 넣기

from prefetch_related.models import Topping, Pizza

q=Topping(name="양파")
q.save()
q=Topping(name="고구마")
q.save()
q=Topping(name="감자")
q.save()

Topping.objects.all()
<QuerySet [<Topping: 양파>, <Topping: 고구마>, <Topping: 감자>]>

2. prefetch_related 

>>> Pizza.objects.all()
<QuerySet [<Pizza: 고구마 피자 (양파, 고구마)>, <Pizza: 포테이토 피자 (양파, 감자)>]>

Pizza.objects.all()은 요청할 때마다 self.toppings.all() 데이터베이스를 쿼리해야 하므로 

모든 피자 항목에 대해 Toppings 테이블에서 쿼리를 실행한다.

>>> Pizza.objects.prefetch_related('toppings')
<QuerySet [<Pizza: 고구마 피자 (양파, 고구마)>, <Pizza: 포테이토 피자 (양파, 감자)>]>

prefetch_related('toppings)는 self.toppings.all()을 의미하며 self.toppings.all() 항목에 대한 데이터 베이스로 이동하여 쿼리를 실행하지 않고 미리 단일 쿼리로 채워진  캐시를 읽어 쿼리를 실행한다.

In [44]: Topping.objects.all()
Out[44]: <QuerySet [<Topping: 양파>, <Topping: 고구마>, <Topping: 감자>, <Topping: 치즈>, <Topping: 불고기>]>

Toppings의 모든 객체를 읽어 오지 않고 관련 객체만 읽어 오므로 쿼리 속도가 빨라진다.

예를 들면 고구마 피자의 토핑에는  양파, 고구마 두가지가 있는데 이 데이터를 가져올때 모든 토핑을 거치지 않고 미리 캐시에 저장된 두 가지 토핑만 읽으면 된다.