Hämtningslägen¶
När du använder modellfält som inte lästes in som en del av den ursprungliga frågan hämtar Django fältets data från databasen. Du kan anpassa hur denna hämtning fungerar med ett hämtningsläge, för att göra den mer effektiv eller till och med blockera den.
Använd QuerySet.fetch_mode() för att ange hämtningsläge för modellinstanser som hämtas av en QuerySet:
from django.db import models
books = Book.objects.fetch_mode(models.FETCH_PEERS)
Hämtningslägen gäller för:
Fält av typen
ForeignKeyFält av typen
OneToOneFieldoch deras omvända åtkomstfunktionerFält som skjutits upp med
QuerySet.defer()ellerQuerySet.only()
Django kopierar hämtningsläget för en instans till alla relaterade objekt som det hämtar, så läget gäller för ett helt relationsträd, inte bara för toppnivåmodellen i den ursprungliga QuerySet. Kopieringen görs också i relationshanterare, även om hämtningslägen inte påverkar dessa hanterares frågor.
Tillgängliga lägen¶
Referera till hämtningslägen
Hämtningslägen definieras i django.db.models.fetch_modes, men av praktiska skäl importeras de till django.db.models. Standardkonventionen är att använda from django.db import models och referera till hämtningslägen som models.<mode>.
Django tillhandahåller tre hämtningslägen. Vi förklarar dem nedan med hjälp av dessa modeller:
from django.db import models
class Author(models.Model): ...
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
...
…och den här loopen:
for book in books:
print(book.author.name)
…där books är en QuerySet med Book-instanser som använder något hämtningsläge.
- FETCH_ONE¶
Hämtar det saknade fältet endast för den aktuella instansen. Detta är standardläget.
Om du använder FETCH_ONE för exemplet ovan används:
1 fråga för att hämta
booksN frågor, där N är antalet böcker, för att hämta det saknade fältet
author
…vilket ger totalt 1+N frågor. Detta frågemönster kallas ”N+1-frågeproblemet” eftersom det ofta leder till prestandaproblem när N är stort.
- FETCH_PEERS¶
Hämtar det saknade fältet för den aktuella instansen och dess ”peer”-instanser – instanser som kom från samma ursprungliga QuerySet. Lägets beteende bygger på antagandet att om du behöver ett fält för en instans behöver du förmodligen det för alla instanser i samma grupp, eftersom du troligen kommer att behandla dem på samma sätt.
Om du använder FETCH_PEERS för exemplet ovan används:
1 fråga för att hämta
books1 fråga för att hämta alla saknade fält
authorför gruppen av böcker
…vilket ger totalt 2 frågor. Gruppfrågan gör det här läget mycket effektivare än FETCH_ONE och liknar ett anrop vid behov till QuerySet.prefetch_related() eller prefetch_related_objects(). Användning av FETCH_PEERS kan med liten ansträngning minska de flesta fall av ”N+1-frågeproblemet” till två frågor.
”Peer”-instanserna spåras i en lista med svaga referenser, för att undvika minnesläckor när vissa peer-instanser kasseras.
- FETCH_RAISE¶
Utlöser undantaget FieldFetchBlocked.
Om du använder FETCH_RAISE för exemplet ovan utlöses ett undantag när book.author används, så här:
FieldFetchBlocked("Fetching of Primary.value blocked.")
Detta läge kan förhindra oavsiktliga frågor i prestandakritiska delar av koden.
Gör ett hämtningsläge till standard för en modellklass¶
Ange standardhämtningsläge för en modellklass med en anpassad hanterare som åsidosätter get_queryset():
from django.db import models
class BookManager(models.Manager):
def get_queryset(self):
return super().get_queryset().fetch_mode(models.FETCH_PEERS)
class Book(models.Model):
title = models.TextField()
author = models.ForeignKey("Author", on_delete=models.CASCADE)
objects = BookManager()