prefetch_related and select_related provide us with a mechanism to look up objects related to the model that we’re querying. We use prefetch_related when we want to fetch a reverse foreign key or a many to many relationship. We use select related when we want to fetch a foreign key or a one to one relationship.

posts_with_tags = BlogPost.objects.prefetch_related(
    "tags"
).get(id=5)

In this example, we're fetching a single blog post with a specific slug, and with this post we're fetching all of the related tags. This helps us optimize our database queries by loading all the related tags instead of fetching them one by one.

Without prefetch_related, if we looped over tags.all(), each iteration would result in a database query, but with prefetch_related, a loop would result in one database query.

latest_blog_posts = BlogPost.objects.select_related(
    "blog"
).order_by('-published_on')[:15]

select_related works similarly to prefetch_related except we use select_related for different types of relationships. For this case, we're fetching the latest blog post and also fetching the associated blog details.

Once again if we loop over latest_blog_posts, referencing a blog post's blog details won't result in an extra database query.

The order in which you specify select_related are not important. The following two queries are exactly the same:

BlogPost.objects.filter(published_on__gt=timezone.now()).select_related('blog')
BlogPost.objects.select_related('blog').filter(published_on__gt=timezone.now())

You can enable SQL logging if you want to see what's happening behind the scenes.