ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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()의 데이터 크기가 너무 크지 않다면, 메모리에 올려 재사용성을 늘리는 것이 효율적입니다.

    댓글