Weniger Abfragen
Teil des Abschnitts Modelle und Admin-Bereich der Django-Journey von Coddy. Lektion 19 von 23.
Die Startseite gibt den Autor jedes Buchs aus, und das hat seinen Preis: Eine Abfrage ruft die Bücher ab, dann führt {{ book.author.name }} für jedes Buch eine weitere Abfrage aus. Zehn Bücher, elf Abfragen; tausend Bücher, tausendundeine. Das ist das N+1-Problem, ein häufiger Grund dafür, dass eine Django-Seite langsam ist.
select_related() behebt das: Das ORM ruft den verknüpften Datensatz in derselben Abfrage mit einem SQL-JOIN ab. Eine Seite mit Ausleihen, die den Titel des Buchs jeder Ausleihe ausgibt, würde Folgendes abfragen:
loans = Loan.objects.select_related("book")Du übergibst den Namen des ForeignKey-Felds, das du als loan.book ausliest, und es lässt sich weiterhin mit filter() und order_by() verketten. Es folgt ForeignKeys nur vorwärts. Für die Bücher eines Autors und für Many-to-many-Felder brauchst du prefetch_related(), das im Authors-Projekt verwendet wird. Die Seite sieht danach genauso aus, benötigt aber weniger Abfragen.
Aufgabe
MittelSorge in books/views.py dafür, dass die QuerySets in home und search den Autor jedes Buchs in derselben Abfrage abrufen. Behalte den Suchfilter bei.
Klicke auf „Ausführen“: Die Seiten sehen gleich aus. Die Prüfungen fügen zehn Bücher hinzu und erlauben zwei Abfragen pro Seite.
Probier es selbst
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})
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Modelle und Admin-Bereich
Übe selbstständig: Django-Playground