Bij het gebruik van Django ORM zijn er methoden zoals .values() en .only() om alleen specifieke velden op te halen voor prestatieoptimalisatie.
In een vorige post heb ik uitgebreid behandeld wat de .values() methode van Django QuerySet inhoudt. Als je deze nog niet hebt bekeken, raad ik je aan om dit eens te doen. 😊

Om de vorige post te bekijken, klik hier! 

Wat is de .values() methode van Django QuerySet?

Terwijl ik schreef over .values(), dacht ik dat het ook nuttig zou zijn om de .only() methode, die op een vergelijkbare maar andere manier werkt, uit te leggen om een dieper begrip van Django ORM te verkrijgen. Daarom heb ik dit artikel voorbereid. 🚀

1️⃣ Verschillen tussen .only() en .values()

  .only() .values()
Terugkeer formaat Modelinstantie (Model object) Lijst van dictionaries (dict lijst)
Gebruik doel Modelobject behouden + alleen bepaalde velden laden Alleen specifieke velden ophalen en teruggeven in lijst van dictionaries 
ORM functionaliteit behoud ✅ Behoud (gebruik .save(), .delete()) ❗ Geen modelmethoden beschikbaar (.save(), .delete() ❌)
Extra Lazy Loading ❗ Extra query bij toegang tot niet vooraf geladen velden ✅ Geen extra queries

2️⃣ Gebruik en Kenmerken van .only()

.only() is een manier om specifieke velden van een modelobject vooraf te laden terwijl het modelobject behouden blijft. Als je echter toegang probeert te krijgen tot velden die niet vooraf zijn opgegeven, kan Lazy Loading optreden en kunnen er extra queries worden uitgevoerd.

from myapp.models import Post

# QuerySet dat alleen de title en author velden laadt
qs = Post.objects.only("title", "author")

# Controleer de output (QuerySet zelf wordt vertraagd geëvalueerd)
print(qs)  # SQL wordt niet uitgevoerd

# Toegang tot velden
for post in qs:  # ✅ SQL wordt nu uitgevoerd
    print(post.title)  # ✅ Vooraf geladen veld (geen extra query)
    print(post.body)   # 🚨 Niet vooraf geladen veld → extra query komt

🔹 Let op:
.only() laadt alleen de opgegeven velden onmiddellijk en voert extra queries uit voor de andere velden indien nodig.
Daarom is het goed om alle noodzakelijke velden op te geven in .only().

3️⃣ Gebruik en Kenmerken van .values()

.values() haalt alleen specifieke velden op en retourneert deze als een lijst van dictionaries. Omdat het een dictionary retourneert in plaats van een modelobject, kunnen ORM-functies niet worden gebruikt.
Echter, de QuerySet zelf blijft behouden, zodat methoden zoals .filter(), .annotate() nog steeds kunnen worden gebruikt.

# Alleen de title en author velden ophalen maar de resultaten als een dictionary retourneren
qs = Post.objects.values("title", "author")

# De QuerySet zelf wordt vertraagd geëvalueerd (SQL wordt niet uitgevoerd)
print(qs)

# Gebruik van de dictionary data (deze keer SQL wordt uitgevoerd)
for post in qs:
    print(post["title"])  # ✅ Geen extra query

🔹 Let op:
Met .values() worden ForeignKey-velden standaard alleen de ID-waarde geretourneerd.
Dus als er specifieke veldwaarden van het gerelateerde model nodig zijn, moet je dit expliciet opgeven zoals "author__name".

# Specifieke waarde van het ForeignKey-veld ophalen
qs = Post.objects.values("title", "author__name")

for post in qs:
    print(post["author__name"])  # ✅ Haalt de name-veld van het author-object op

In het bovenstaande voorbeeld hebben we het veld "author__name" dat aan een ForeignKey is verbonden opgegeven, dus de verwachte output is author.name, maar als we het gewoon op "author" zouden hebben ingesteld, zou het simpelweg het ID-nummer van het author-object opleveren. 

4️⃣ Wanneer moet je .only() vs .values() gebruiken?

Gebruik doel .only() Aanbevolen .values() Aanbevolen
Als je het modelobject moet behouden
Als je ORM-functies nodig hebt (.save(), .delete(), .update())
Prestatieoptimalisatie (voorkom onnodig laden van velden)
Voorkomen van extra Lazy Loading ❌ (extra query mogelijk) ✅ (geen extra query)

5️⃣ .values() is ook vertraagd geëvalueerd!

Het lijkt misschien of .values() onmiddellijk wordt geëvalueerd, maar in feite is de basisfunctionaliteit van Django's QuerySet allemaal vertraagd geëvalueerd (Lazy Evaluation).
Dit betekent dat op het moment dat je .values() aanroept, SQL niet wordt uitgevoerd totdat je probeert de werkelijke gegevens te gebruiken. 🚀

.values() is ook vertraagd geëvalueerd (SQL wordt niet onmiddellijk uitgevoerd)

qs = Post.objects.values("title", "author")  # ❌ SQL wordt niet uitgevoerd
print(qs)  # ❌ Alleen informatie over het QuerySet-object wordt weergegeven (SQL wordt niet uitgevoerd)

for post in qs:  # ✅ SQL wordt nu uitgevoerd
    print(post["title"])

✅ Wanneer wordt het QuerySet geëvalueerd?

QuerySet met .values() wordt in de volgende gevallen onmiddellijk uitgevoerd (SQL wordt geëvalueerd):

  1. Bij itereren in een for loop
  2. Wanneer list(qs) wordt aangeroepen
  3. Bij aanroepen van bool(qs) (zoals in een voorwaarde if qs:)
  4. Bij aanroepen van methoden zoals .count(), .exists(), .first(), .last()

📌 Conclusie

.only()Modelobject behouden + alleen specifieke velden vooraf laden
     🔹 ORM-functies (.save(), .delete()) zijn beschikbaar
     🔹 Echter, toegang tot niet vooraf geladen velden leidt tot extra queries

.values()Retourneert lijst van dictionaries + geen extra queries
     🔹 Geen modelobject, dus .save(), .delete() kunnen niet gebruikt worden
     🔹 QuerySet zelf blijft behouden, dus gebruik .filter(), .annotate()
     🔹 ForeignKey-velden retourneren standaard alleen de ID-waarde → dit moet expliciet worden opgegeven zoals author__name

💡 Als je het modelobject moet behouden, gebruik dan .only(), en kies .values() voor eenvoudige dataverzameling! 🚀

🎯 Prestatieoptimalisatie is belangrijk bij het gebruik van Django ORM.

Als je twijfelt welke functie je moet gebruiken, raadpleeg dan dit artikel om de beste methode voor jouw applicatie te kiezen.
Ik wens je project veel efficiëntie en snelheid! 🔥

Django QuerySet .only() vs .values() flowchart