Funcionalidades potentes del Django ORM con el objeto django.db.models.F
Cuando trabajas con Django, a menudo surge la necesidad de realizar operaciones complejas sin escribir consultas SQL directamente. En esos momentos, el objeto django.db.models.F resulta invaluable. En esta publicación veremos qué es, cuándo y cómo usarlo, y presentaremos varios ejemplos de la vida real.
1. ¿Qué es el objeto F?
El objeto F es una expresión que referencia el valor de un campo en la base de datos. En otras palabras, permite leer el valor de un campo a nivel de base de datos y usarlo en comparaciones o cálculos con otros campos.
from django.db.models import F
Punto clave - El objeto
Fno es un objeto Python, sino que se convierte en una expresión SQL. - Al usarF, la operación se ejecuta directamente en la base de datos, lo que mejora el rendimiento frente a la obtención de valores en Python.
2. ¿Por qué necesitamos el objeto F?
2‑1. Evitar problemas de concurrencia
Imagina el siguiente escenario:
product.stock -= 1
product.save()
Si dos usuarios compran el mismo producto simultáneamente, el primer usuario reduce el stock en 1 y guarda el cambio, mientras que el segundo lee el mismo valor y lo reduce de nuevo. El resultado es que el stock se reduce en 2, lo cual es incorrecto.
Con F, la base de datos decrementa el valor de forma atómica, evitando este problema:
Product.objects.filter(id=product_id).update(stock=F('stock') - 1)
2‑2. Filtrado complejo
El objeto F permite comparar campos entre sí.
# Obtener productos cuyo precio sea mayor que el precio con descuento
Product.objects.filter(price__gt=F('discount_price'))
2‑3. Actualizaciones masivas
Con F puedes actualizar muchos registros con una sola consulta.
# Aumentar el precio de todos los productos en un 10 %
Product.objects.update(price=F('price') * 1.10)
3. Cómo usar el objeto F
3‑1. Uso básico
from django.db.models import F
# Comparar campos
qs = Book.objects.filter(pages__gt=F('chapters'))
# Operar entre campos
qs = Book.objects.update(pages=F('pages') + 10)
3‑2. Combinar F con Q
Q permite construir condiciones complejas.
from django.db.models import Q
qs = Book.objects.filter(
Q(pages__gt=F('chapters')) | Q(pages__lt=F('pages') * 2)
)
3‑3. Usar F con annotate
annotate crea campos virtuales.
from django.db.models import F, Value, FloatField
qs = Book.objects.annotate(
ratio=F('pages') / F('chapters')
).filter(ratio__gt=5)
Precaución: Algunas operaciones con
Fpueden no estar soportadas por todas las bases de datos. Por ejemplo, SQLite puede no admitir multiplicaciones conF. Prueba antes de usar.
4. Ejemplos prácticos
4‑1. Gestión de inventario
# Reducir el stock en 1 y desactivar si llega a 0
Product.objects.filter(id=product_id, stock__gt=0).update(
stock=F('stock') - 1,
is_active=Case(
When(stock=1, then=Value(False)),
default=Value(True),
output_field=BooleanField()
)
)
4‑2. Calcular tasa de descuento
# Obtener productos con descuento mayor o igual al 20 %
Product.objects.annotate(
discount_rate=F('discount_price') / F('price')
).filter(discount_rate__gte=0.2)
4‑3. Aumento masivo de precios
# Incrementar el precio de todos los productos de la categoría "electronics" en 15 %
Product.objects.filter(category='electronics').update(
price=F('price') * 1.15
)
5. Consejos para usar F
| Situación | Uso recomendado |
|---|---|
| Concurrencia | update() + F |
| Comparación de campos | filter(field__gt=F('other_field')) |
| Campo virtual | annotate(new_field=F('field1') + F('field2')) |
| Actualización condicional | Case + When + F |
Tip: Las consultas con
Fse convierten directamente a SQL, por lo que es útil revisar el plan de ejecución con herramientas de profiling.
6. Conclusión
El objeto django.db.models.F permite realizar operaciones a nivel de base de datos de forma eficiente y segura. Resuelve problemas de concurrencia, simplifica filtros complejos y facilita actualizaciones masivas. Si quieres aprovechar al máximo Django ORM, incorpora F en tu flujo de trabajo.

Recursos adicionales - Documentación oficial de Django: F expressions - Código de ejemplo: GitHub Gist
¡Feliz codificación! 🚀
No hay comentarios.