-
[Django] Prefetch()를 사용한다면 to_attr 속성을 같이 사용하자언어/파이썬 & 장고 2019. 2. 2. 17:35
ORM을 조인하고 싶을 때 N:1의 관계나 N:N의 관계일 경우, prefetch_related()를 사용하게 됩니다.
모델 정의
예시를 들기 위해 아래와 같이 모델과 모델간 관계를 정의합니다.
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) vegetarian = models.BooleanField() def __str__(self): return "%s (%s)" % ( self.name, ", ".join(topping.name for topping in self.toppings.all()), ) class Restaurant(models.Model): pizzas = models.ManyToManyField(Pizza, related_name='restaurants') best_pizza = models.ForeignKey(Pizza, related_name='championed_by', on_delete=models.CASCADE)
Prefetch
만약 첫 번째 레스토랑에서 채식주의자가 먹을 수 있는 피자를 조회하는 쿼리는 아래와 같습니다.
queryset = Pizza.objects.filter(vegetarian=True) restaurants = Restaurant.objects.prefetch_related(Prefetch('pizzas', queryset=queryset)) vegetarian_pizzas = restaurants[0].pizzas.all()
만약 위와 같은 queryset이 다른 조인 쿼리에도 사용된다면 해당 쿼리가 실행될 때마다 새로 조회를 하므로 중복조회가 발생됩니다. 이때, Prefetch()에서 제공하는 to_attr을 사용하여 쿼리를 메모리에 저장하여 효율적으로 사용할 수 있습니다.
queryset = Pizza.objects.filter(vegetarian=True) restaurants = Restaurant.objects.prefetch_related(Prefetch('pizzas', queryset=queryset, to_attr='vegetarian_pizzas')) vegetarian_pizzas = restaurants[0].vegetarian_pizzas
to_attr에 저장되는 Prefetch()의 데이터 크기가 너무 크지 않다면, 메모리에 올려 재사용성을 늘리는 것이 효율적입니다.