Check out an example from django docs with the Pizza and Topping models. One pizza can have several toppings.
If we make a request:
pizzas = Pizza.objects.prefetch_related('toppings')
We will get all the pizzas and their filling in 2 requests. Now suppose I want to pre-select only vegetarian fillings (suppose we have this property):
pizzas = Pizza.objects.prefetch_related( Prefetch('toppings', queryset=Topping.objects.filter(is_vegetarian=True)) )
This works very well, and Django does not do another request for every pizza, doing something like this:
for pizza in pizzas: print(pizza.toppings.filter(is_vegetarian=True))
Now suppose we have a user manager for the Topping model, and we decided to put a method there that allows us to filter only vegetarian fillings, as in the above code example:
class ToppingManager(models.Manager): def filter_vegetarian(self): return self.filter(is_vegetarian=True)
Now I make a new request and pre-select a user request with my method from the manager:
pizzas = Pizza.objects.prefetch_related( Prefetch('toppings', queryset=Topping.objects.filter_vegetarian()))
And try to execute my code:
for pizza in pizzas: print(pizza.toppings.filter_vegeterian())
I get a new request for each iteration of the loop. This is my question. What for? Both of these constructs return an object of the same type as the query:
Topping.objects.filter_vegetarian() Topping.objects.filter(is_vegetarian=True)