Let's look at example from django docs with Pizza and Topping models. One pizza may have multiple toppings.
If we make a query:
pizzas = Pizza.objects.prefetch_related('toppings')
We'll get all the pizzas and their toppings in 2 queries. Now let's suppose that I want to prefetch only vegetarian toppings (assume we have such property):
pizzas = Pizza.objects.prefetch_related(
Prefetch('toppings', queryset=Topping.objects.filter(is_vegetarian=True))
)
It works pretty well and Django doesn't perform yet another query for each pizza, when making something like this:
for pizza in pizzas:
print(pizza.toppings.filter(is_vegetarian=True))
Now let's suppose We have a custom manager for Topping model and we decided to put there a method that allows us to filter only vegetarian toppings like in code example above:
class ToppingManager(models.Manager):
def filter_vegetarian(self):
return self.filter(is_vegetarian=True)
Now I make a new query and prefetch custom queryset with my method from manager:
pizzas = Pizza.objects.prefetch_related(
Prefetch('toppings', queryset=Topping.objects.filter_vegetarian()))
And the try to execute my code:
for pizza in pizzas:
print(pizza.toppings.filter_vegeterian())
I get a new one query for each iteration of the loop. That is my question. Why? Both these constructions return the same type object which is queryset:
Topping.objects.filter_vegetarian()
Topping.objects.filter(is_vegetarian=True)