Django prefetch_related performance - to_attr not working on nested lookups

Viewed 994

I have a relatively complex model structure in a django project (v2.1.4). Let's say:

class Pizza(models.Model):
    pass

class ToppingPlacedOnPizza(models.Model):
    # Breaks a many-to-many relationship between Pizza and Topping and stores specific data
    # like the position of the topping in the pizza
    pizza = models.ForeignKey(Pizza, related_name='placed_toppings')
    topping = models.ForeignKey(Topping)
    # position ...

class Topping(models.Model):
    brand = models.ForeignKey(Brand)

class Brand(models.Model):
    name = models.CharField(max_length=32)

I need to retrieve all the names of the brands that make toppings for each pizza of a set of pizzas. Say:

pizza1: brand1, brand2, brand3
pizza2: brand2, brand4
...

To do so, prefetch_related has been of great help in order to improve performance:

pizzas.prefetch_related('placed_toppings__topping__brand')

But when making a query for ~1000 pizzas it starts being really slow. According to this stackoverflow answer, using Prefetch class and to_attr could improve performance, but I couldn't make it work on my case. It's not clear in which object to_attr will write the new attribute because of the nested lookup.

I made to_attr work on first level. When setting pizzas.prefetch_related(Prefetch('placed_toppings', to_attr('mytoppings'))), then pizzas[0].mytoppings exists.

But when setting pizzas.prefetch_related(Prefetch('placed_toppings__topping__brand', to_attr('mybrands'))), none of the following exist:

pizzas.mybrands
pizzas[0].mybrands
pizzas[0].placed_toppings.mybrands
pizzas[0].placed_toppings.first().mybrands
pizzas[0].placed_toppings.first().topping.mybrands

Any ideas on how to improve performance or make to_attr work on nested lookups?

0 Answers
Related