Gone through the already posted answers. Just thought it would be better if I add an answer with actual example.
Let' say you have 3 Django models which are related.
class M1(models.Model):
name = models.CharField(max_length=10)
class M2(models.Model):
name = models.CharField(max_length=10)
select_relation = models.ForeignKey(M1, on_delete=models.CASCADE)
prefetch_relation = models.ManyToManyField(to='M3')
class M3(models.Model):
name = models.CharField(max_length=10)
Here you can query M2 model and its relative M1 objects using select_relation field and M3 objects using prefetch_relation field.
However as we've mentioned M1's relation from M2 is a ForeignKey, it just returns only 1 record for any M2 object. Same thing applies for OneToOneField as well.
But M3's relation from M2 is a ManyToManyField which might return any number of M1 objects.
Consider a case where you have 2 M2 objects m21, m22 who have same 5 associated M3 objects with IDs 1,2,3,4,5. When you fetch associated M3 objects for each of those M2 objects, if you use select related, this is how it's going to work.
Steps:
- Find
m21 object.
- Query all the
M3 objects related to m21 object whose IDs are 1,2,3,4,5.
- Repeat same thing for
m22 object and all other M2 objects.
As we have same 1,2,3,4,5 IDs for both m21, m22 objects, if we use select_related option, it's going to query the DB twice for the same IDs which were already fetched.
Instead if you use prefetch_related, when you try to get M2 objects, it will make a note of all the IDs that your objects returned (Note: only the IDs) while querying M2 table and as last step, Django is going to make a query to M3 table with the set of all IDs that your M2 objects have returned. and join them to M2 objects using Python instead of database.
This way you're querying all the M3 objects only once which improves performance.