Lors de l'utilisation de Django ORM, il existe deux méthodes pour récupérer uniquement certains champs dans le but d'optimiser les performances : .values() et .only().
Dans un précédent article, j'ai abordé en détail la méthode .values() de Django QuerySet. Si vous ne l'avez pas encore consulté, je vous recommande de le faire. 😊

Pour consulter l'article précédent, cliquez ici ! 

Qu'est-ce que la méthode .values() de Django QuerySet ?

En écrivant sur .values(), je pense que l'explication de la méthode .only(), qui fonctionne de manière similaire mais différemment, pourra vous aider à mieux comprendre Django ORM. C'est pourquoi j'ai préparé cet article. 🚀

1️⃣ Différences entre .only() et .values()

  .only() .values()
Type de retour Instance de modèle (objet Model) Liste de dictionnaires (dict list)
But d'utilisation Conserver l'objet modèle + charger seulement quelques champs Récupérer uniquement certains champs et retourner un QuerySet sous forme de liste de dictionnaires 
Fonctionnalité ORM ✅ Maintenue (.save(), .delete() utilisables) ❗ Méthodes de modèle non disponibles (.save(), .delete() ❌)
Lazy Loading supplémentaire ❗ Des requêtes supplémentaires peuvent se produire lors de l'accès à des champs non préchargés ✅ Pas de requêtes supplémentaires

2️⃣ Utilisation et caractéristiques de .only()

.only() est une méthode qui maintient l'objet modèle tout en préchargeant uniquement certains champs. Cependant, si vous accédez à des champs non spécifiés à l'avance, cela pourrait entraîner Lazy Loading et exécuter des requêtes supplémentaires.

from myapp.models import Post

# QuerySet chargeant uniquement les champs title et author
qs = Post.objects.only("title", "author")

# Vérification de la sortie (le QuerySet lui-même est évalué de manière paresseuse)
print(qs)  # SQL non exécuté

# Accès aux champs
for post in qs:  # ✅ À ce moment, le SQL est exécuté
    print(post.title)  # ✅ Champ préchargé (pas de requête supplémentaire)
    print(post.body)   # 🚨 Champ non préchargé → requête supplémentaire

🔹 Point important :
.only() charge uniquement les champs spécifiés immédiatement, et les autres champs nécessiteront des requêtes supplémentaires lors de leur chargement.
Pour éviter des requêtes inutiles, il est donc recommandé de spécifier tous les champs nécessaires dans .only().

3️⃣ Utilisation et caractéristiques de .values()

.values() récupère uniquement des champs spécifiques et retourne sous forme de liste de dictionnaires. Étant donné qu'elle retourne un dictionnaire au lieu d'un objet de modèle, vous ne pouvez pas utiliser les fonctionnalités ORM.
Cependant, le QuerySet lui-même est maintenu, donc vous pouvez continuer à utiliser des méthodes comme .filter(), .annotate().

# Récupérer uniquement les champs title et author sous forme de dictionnaire
qs = Post.objects.values("title", "author")

# Le QuerySet lui-même est évalué de manière paresseuse (SQL non exécuté)
print(qs)

# Utilisation des données sous forme de dictionnaire (SQL exécuté à ce moment)
for post in qs:
    print(post["title"])  # ✅ Pas de requête supplémentaire

🔹 Point important :
Lorsque vous utilisez .values(), les champs ForeignKey retournent par défaut uniquement les valeurs ID.
Ainsi, si vous avez besoin d'un champ spécifique d'un modèle lié, vous devez le spécifier clairement comme "author__name".

# Récupérer une valeur particulière d'un champ ForeignKey
qs = Post.objects.values("title", "author__name")

for post in qs:
    print(post["author__name"])  # ✅ Récupération du champ name de l'objet author

Dans cet exemple, comme nous avons spécifié le champ "author__name" lié par ForeignKey, nous obtiendrons la valeur attendue de author.name. Si nous avions seulement spécifié "author", nous n'aurions obtenu que l'ID de l'objet author. 

4️⃣ Quand utiliser .only() vs .values() ?

But d'utilisation .only() recommandé .values() recommandé
Lorsque l'objet modèle doit être conservé
Besoin d'utiliser les fonctionnalités ORM (.save(), .delete(), .update())
Optimisation des performances (éviter le chargement de champs non nécessaires)
Prévenir le Lazy Loading supplémentaire ❌ (requêtes supplémentaires possibles) ✅ (pas de requêtes supplémentaires)

5️⃣ .values() est également évalué de manière paresseuse !

.values() peut sembler être évalué immédiatement, mais en réalité, le QuerySet de Django est, par défaut, tous évalués de manière paresseuse.
Ainsi, lorsque vous appelez .values(), SQL n'est pas exécuté immédiatement. Cela se produit uniquement lorsque vous essayez d'utiliser les données réelles. 🚀

.values() est également évalué de manière paresseuse (SQL non exécuté immédiatement)

qs = Post.objects.values("title", "author")  # ❌ SQL n'est pas exécuté
print(qs)  # ❌ Affiche seulement les informations sur l'objet QuerySet (SQL non exécuté)

for post in qs:  # ✅ À ce moment-là SQL est exécuté
    print(post["title"])

✅ Quand le QuerySet est-il évalué ?

Un QuerySet contenant .values() est évalué immédiatement (SQL exécuté) dans les cas suivants :

  1. Lors de la itération avec for
  2. Lorsque vous appelez list(qs)
  3. Lorsque vous appelez bool(qs) (comme dans une condition if qs:)
  4. Lors de l'appel de méthodes comme .count(), .exists(), .first(), .last(), etc.

📌 Conclusion

.only()Maintient l'objet modèle + précharge uniquement certains champs
     🔹 Fonctionnalités ORM (.save(), .delete()) utilisables
     🔹 Cependant, des requêtes supplémentaires peuvent se produire lors de l'accès à des champs non préchargés

.values()Retourne une liste de dictionnaires + pas de requêtes supplémentaires
     🔹 Comme ce n'est pas un objet modèle, .save(), .delete() ne sont pas utilisables
     🔹 Maintient le QuerySet lui-même, donc .filter(), .annotate() peuvent être utilisés
     🔹 Les champs ForeignKey retournent par défaut uniquement les valeurs ID → doit être spécifié comme author__name

💡 Autrement dit, si vous devez maintenir un objet modèle, choisissez .only(), et pour une simple récupération de données, choisissez .values()! 🚀

🎯 L'optimisation des performances est essentielle lors de l'utilisation de Django ORM.

Lorsque vous êtes incertain sur quelle fonctionnalité utiliser, référez-vous à cet article pour choisir la méthode optimale pour votre application.
Je vous souhaite de voir votre projet fonctionner de manière plus efficace et rapide! 🔥

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