Menu
CoddyTech

Fewer Queries

Part of the Models and the Admin section of Coddy's Django journey. Lesson 19 of 23.

The home page prints each book's author, and that has a cost: one query fetches the books, then {{ book.author.name }} runs one more query per book. Ten books, eleven queries; a thousand books, a thousand and one. This is the N+1 problem, a common reason a Django page is slow.

select_related() fixes it: the ORM fetches the related row in the same query, with a SQL JOIN. A page of loans that prints each loan's book title would ask for:

loans = Loan.objects.select_related("book")

You give it the name of the ForeignKey field, the one you read as loan.book, and it still chains with filter() and order_by(). It follows ForeignKeys forward only; the way back and many-to-many fields take prefetch_related(), met in the Authors project. The page looks the same afterwards, with fewer queries.

challenge icon

Challenge

Medium

The home page and the search page both show each book's author. Make each fetch the authors together with the books, so the number of queries stays the same however many books there are:

  • the home view
  • the search view

Press Run: the pages look the same. The checks count the queries.

Try it yourself

from django.shortcuts import get_object_or_404, render

from .models import Book


def home(request):
    books = Book.objects.all()
    return render(request, "books/home.html", {"books": books})


def book_detail(request, pk):
    book = get_object_or_404(Book, pk=pk)
    return render(request, "books/book_detail.html", {"book": book})


def search(request):
    q = request.GET.get("q", "")
    books = Book.objects.filter(title__icontains=q)
    return render(request, "books/search.html", {"q": q, "books": books})
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Models and the Admin

Practice on your own: Django playground