Al usar Django ORM, hay métodos como .values()
y .only()
para optimizar el rendimiento al traer solo campos específicos.
En una publicación anterior, traté detalladamente sobre ¿Qué es el método .values()
de Django QuerySet?, así que si aún no lo has revisado, ¡te recomiendo que lo hagas! 😊
¡Haz clic para revisar el post anterior!
¿Qué es el método .values()
de Django QuerySet?
Al escribir sobre .values()
, pensé que sería útil explicar también el método .only()
, que funciona de manera similar pero diferente, para ayudar a entender mejor Django ORM, así que preparé esta publicación. 🚀
1️⃣ Diferencias entre .only()
y .values()
.only() |
.values() |
|
---|---|---|
Forma de retorno | Instancia del modelo (objeto Model) | Lista de diccionarios (dict list) |
Propósito de uso | Mantener objeto modelo + cargar solo algunos campos | Retornar un conjunto de consulta en forma de lista de diccionarios con solo campos específicos |
Conservación de las funciones ORM | ✅ Conservado (.save() , .delete() disponibles) |
❗ Métodos del modelo no disponibles (.save() , .delete() ❌) |
Carga perezosa adicional | ❗ Genera consultas adicionales al acceder a campos no precargados | ✅ Sin consultas adicionales |
2️⃣ Uso y características de .only()
.only()
es un método que permite mantener el objeto del modelo mientras solo se precargan ciertos campos. Si accedes a campos que no han sido especificados, puede ocurrir carga perezosa, lo que generará consultas adicionales.
from myapp.models import Post
# Cargar solo los campos title y author
qs = Post.objects.only("title", "author")
# Verificación de impresión (el QuerySet en sí se evalúa de manera diferida)
print(qs) # SQL no se ejecuta
# Acceso a los campos
for post in qs: # ✅ En este punto se ejecuta SQL
print(post.title) # ✅ Campo precargado (sin consulta adicional)
print(post.body) # 🚨 Campo no precargado → consulta adicional generada
🔹 Punto a considerar:
.only()
carga inmediatamente solo los campos especificados, y ejecuta consultas adicionales para los campos restantes según sea necesario.
Por lo tanto, para evitar consultas innecesarias, es recomendable especificar todos los campos necesarios en .only()
.
3️⃣ Uso y características de .values()
.values()
retorna solo ciertos campos en forma de lista de diccionarios. No retorna objetos modelo, por lo que no se pueden utilizar funciones ORM.
Sin embargo, el QuerySet en sí se conserva, por lo que aún puedes usar métodos como .filter()
y .annotate()
.
# Solo trae los campos title y author, retornando el resultado en formato de diccionario
qs = Post.objects.values("title", "author")
# El QuerySet en sí se evalúa de manera diferida (no se ejecuta SQL)
print(qs)
# Utilizando datos de diccionario (en ese momento se ejecuta SQL)
for post in qs:
print(post["title"]) # ✅ Sin consulta adicional
🔹 Punto a considerar:
Al usar .values()
, los campos ForeignKey por defecto solo retornan el valor ID.
Para obtener valores de campos específicos del modelo relacionado, debes especificarlo explícitamente como "author__name"
.
# Obtener un valor específico de un campo ForeignKey
qs = Post.objects.values("title", "author__name")
for post in qs:
print(post["author__name"]) # ✅ Trae el campo name del objeto author
En el ejemplo anterior, como especificamos el campo "author__name"
relacionado con ForeignKey, obtendremos como resultado lo que se pretendía de author.name. Sin embargo, si hubiéramos especificado solo "author"
, simplemente habríamos obtenido el número ID del objeto author.
4️⃣ ¿Cuándo deberías usar .only()
vs .values()
?
Propósito de uso | Recomendado para .only() |
Recomendado para .values() |
---|---|---|
Cuando necesites mantener el objeto modelo | ✅ | ❌ |
Cuando necesites usar funciones ORM (.save() , .delete() , .update() ) |
✅ | ❌ |
Optimización del rendimiento (evitar carga de campos innecesarios) | ✅ | ✅ |
Evitar carga perezosa adicional | ❌ (puede generar consultas adicionales) | ✅ (sin consultas adicionales) |
5️⃣ ¡.values()
también se evalúa de forma diferida!
Puede parecer que .values()
se evalúa inmediatamente, pero en realidad, el QuerySet de Django se evalúa de manera toda diferida (Lazy Evaluation).
Es decir, no se ejecuta SQL en el momento de llamar a .values()
, sino cuando realmente se usa la información. 🚀
✅ .values()
también se evalúa de manera diferida (SQL no se ejecuta de inmediato)
qs = Post.objects.values("title", "author") # ❌ SQL no se ejecuta
print(qs) # ❌ Solo se imprime información sobre el objeto QuerySet (SQL no se ejecuta)
for post in qs: # ✅ En este momento se ejecuta SQL
print(post["title"])
✅ ¿Cuándo se evalúa un QuerySet?
Un QuerySet que incluye .values()
se ejecuta inmediatamente (evaluación SQL) en los siguientes casos:
- Al iterar sobre él en un
for
- Cuando se llama a
list(qs)
- Cuando se llama a
bool(qs)
(en condiciones comoif qs:
) - Al llamar a métodos como
.count()
,.exists()
,.first()
,.last()
, etc.
📌 Conclusión
✅ .only()
→ mantener el objeto modelo + precargar solo ciertos campos
🔹 Se pueden usar funciones ORM (.save()
, .delete()
)
🔹 Sin embargo, acceder a campos no precargados genera consultas adicionales
✅ .values()
→ retorna una lista de diccionarios + sin consultas adicionales
🔹 No es un objeto modelo, por lo que no se pueden usar .save()
, .delete()
🔹 El QuerySet se conserva, por lo que puedes usar .filter()
, .annotate()
🔹 Los campos ForeignKey devuelven por defecto solo el valor ID → debe especificarse como author__name
💡 En resumen, si necesitas mantener el objeto modelo, opta por .only()
; si solo necesitas consultar datos, elige .values()
! 🚀
🎯 Es importante optimizar el rendimiento al usar Django ORM.
Cuando dudes sobre qué función utilizar, consulta este artículo para seleccionar la mejor manera para tu aplicación.
¡Espero que tu proyecto funcione de manera más eficiente y rápida! 🔥
Add a New Comment