Beim Einsatz von Django ORM gibt es die Methoden .values() und .only(), um zur Leistungsoptimierung nur bestimmte Felder abzurufen.
Ich habe in einem vorherigen Beitrag ausführlich über die Methode .values() des Django QuerySet geschrieben. Falls Sie noch nicht dazu gekommen sind, empfehle ich Ihnen, einen Blick darauf zu werfen. 😊

Um den vorherigen Beitrag anzusehen, klicken Sie hier! 

Was ist die .values() Methode des Django QuerySet?

Da ich über .values() schreibe, dachte ich, dass es sinnvoll wäre, auch die .only() Methode, die ähnlich, aber anders funktioniert, zu erläutern, um ein tieferes Verständnis des Django ORM zu erreichen. Daher habe ich diesen Beitrag vorbereitet. 🚀

1️⃣ Unterschiede zwischen .only() und .values()

  .only() .values()
Rückgabeformat Modellinstanz (Model-Objekt) Liste von Dictionaires (dict list)
Verwendungszweck Modellobjekt beibehalten + nur einzelne Felder laden Nur bestimmte Felder abrufen und eine Liste von Dictionaires zurückgeben
Beibehaltung von ORM-Funktionen ✅ Beibehalten (.save(), .delete() verfügbar) ❗ Modellmethoden nicht verfügbar (.save(), .delete() ❌)
Zusätzliche Lazy Loading ❗ Zusätzliche Abfragen bei Zugriff auf nicht vorab geladene Felder ✅ Keine zusätzlichen Abfragen

2️⃣ Verwendung und Merkmale von .only()

.only() ist ein Weg, um das Modellobjekt beizubehalten und nur bestimmte Felder vorzuladen. Wenn jedoch auf nicht vorab festgelegte Felder zugegriffen wird, kann Lazy Loading auftreten, was zusätzliche Abfragen zur Folge hat.

from myapp.models import Post

# QuerySet, das nur die Felder title und author lädt
qs = Post.objects.only("title", "author")

# Überprüfung der Ausgabe (Das QuerySet selbst wird verzögert bewertet)
print(qs)  # SQL wird nicht ausgeführt

# Zugriff auf Felder
for post in qs:  # ✅ Jetzt wird SQL ausgeführt
    print(post.title)  # ✅ Vorab geladenes Feld (keine zusätzlichen Abfragen)
    print(post.body)   # 🚨 Nicht vorab geladenes Feld → zusätzliche Abfrage

🔹 Hinweis:
.only() lädt nur die angegebenen Felder sofort und führt zusätzliche Abfragen für die verbleibenden Felder aus, wenn sie benötigt werden.
Um unnötige Abfragen zu vermeiden, ist es daher ratsam, alle benötigten Felder in .only() anzugeben.

3️⃣ Verwendung und Merkmale von .values()

.values() gibt nur bestimmte Felder in Form einer Liste von Dictionaires zurück. Da ein Dictionaire zurückgegeben wird und kein Modellobjekt, stehen die ORM-Funktionen nicht zur Verfügung.
Das QuerySet selbst bleibt jedoch erhalten, sodass Methoden wie .filter(), .annotate() weiterhin verwendet werden können.

# Lade nur die Felder title und author und gebe das Ergebnis als Dictionaire zurück
qs = Post.objects.values("title", "author")

# Das QuerySet selbst wird verzögert bewertet (SQL wird nicht ausgeführt)
print(qs)

# Verwendung der Dictionaire-Daten (jetzt wird SQL ausgeführt)
for post in qs:
    print(post["title"])  # ✅ Keine zusätzlichen Abfragen

🔹 Hinweis:
Bei der Verwendung von .values() gibt ForeignKey-Felder standardmäßig nur die ID-Werte zurück.
Um spezifische Werte eines zugehörigen Modells zu erhalten, muss dies explizit angegeben werden, z.B. "author__name".

# spezifischen Wert eines ForeignKey-Feldes abrufen
qs = Post.objects.values("title", "author__name")

for post in qs:
    print(post["author__name"])  # ✅ Name-Feld des author-Objekts abrufen

Im obigen Beispielcode haben wir das "author__name" Feld angegeben, daher wird der beabsichtigte author.name ausgegeben. Wenn wir jedoch "author" angegeben hätten, würde einfach nur die ID des author-Objekts ausgegeben werden.  

4️⃣ Wann sollte man .only() vs .values() verwenden?

Verwendungszweck .only() empfohlen .values() empfohlen
Wenn das Modellobjekt beibehalten werden muss
Wenn ORM-Funktionen (.save(), .delete(), .update()) benötigt werden
Zur Leistungsoptimierung (Vermeidung unnötiger Felder)
Vermeidung zusätzlicher Lazy Loading ❌ (zusätzliche Abfragen möglich) ✅ (keine zusätzlichen Abfragen)

5️⃣ .values() ist ebenfalls verzögert bewertet!

.values() kann wie eine sofortige Bewertung erscheinen, aber tatsächlich ist das QuerySet von Django grundsätzlich alle auf Lazy Evaluation ausgelegt.
Das bedeutet, dass .values() nicht beim Aufruf SQL ausgeführt wird, sondern bewertet wird, wenn die tatsächlichen Daten verwendet werden. 🚀

.values() wird ebenfalls verzögert bewertet (SQL wird nicht sofort ausgeführt)

qs = Post.objects.values("title", "author")  # ❌ SQL wird nicht ausgeführt
print(qs)  # ❌ Es wird nur die Information des QuerySet-Objekts angezeigt (SQL wird nicht ausgeführt)

for post in qs:  # ✅ An diesem Punkt wird SQL ausgeführt
    print(post["title"])

✅ Wann wird ein QuerySet bewertet?

Ein QuerySet, das .values() enthält, wird in folgenden Fällen sofort ausgeführt (SQL wird bewertet):

  1. Wenn es in einer for-Schleife durchlaufen wird
  2. Wenn list(qs) aufgerufen wird
  3. Wenn bool(qs) (if qs: in einer Bedingung) aufgerufen wird
  4. Wenn Methoden wie .count(), .exists(), .first(), .last() aufgerufen werden

📌 Fazit

.only()Modellobjekt beibehalten + nur bestimmte Felder müssen vorgeladen werden
     🔹 ORM-Funktionen (.save(), .delete()) sind verfügbar
     🔹 Allerdings können zusätzliche Abfragen entstehen, wenn nicht vorab geladene Felder zugegriffen werden

.values()Liste von Dictionaires zurückgeben + keine zusätzlichen Abfragen
     🔹 Da es kein Modellobjekt ist, können .save(), .delete() nicht verwendet werden
     🔹 Das QuerySet bleibt jedoch erhalten, sodass .filter(), .annotate() verwendet werden kann
     🔹 ForeignKey-Felder geben standardmäßig nur die ID-Werte zurück → müssen wie author__name spezifiziert werden

💡 Wenn Sie das Modellobjekt beibehalten müssen, verwenden Sie .only(), und wählen Sie .values() für einfache Datenabfragen! 🚀

🎯 Leistungsoptimierung ist wichtig beim Arbeiten mit Django ORM.

Wenn Sie unsicher sind, welche Funktion zu verwenden ist, lesen Sie diesen Beitrag und wählen Sie den besten Ansatz für Ihre Anwendung aus.
Ich wünsche Ihnen viel Erfolg, damit Ihr Projekt effizienter und schneller läuft! 🔥

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