Por ejemplo, tenemos unos movimientos en los que interviene cantidad, precio y comisión. ¿Qué sentido tiene guardar en la BD el campo importe si en realidad ya tenemos toda la información para calcularlo?.
class Movimiento(models.Model):
cantidad=models.DecimalField()
precio=models.DecimalField()
comision=models.DecimalField()
¿Cómo calculamos entonces el importe?. Hay dos alternativas: Una usando una property de python en el propio objeto model y otra usando extra en el queryset. Veamos:
class Movimiento(models.Model):
cantidad=models.DecimalField()
precio=models.DecimalField()
comision=models.DecimalField()
def _get_importe(self):
return self.cantidad*self.cambio*(1-self.comision)
importe = property(_get_importe)
Y ahí tenemos el importe del movimiento via movimiento.importeLa otra solución es usar extra en el queryset para añadir "a mano" el campo en la consulta SQL, sería:
target=movimiento.objects.extra(select={
'importe': 'cantidad*cambio*(1-comision)',})
for f in target:
print f.importe
Entonces, ¿Cuál es el problema?. Pues que todo esto son soluciones "de mentirijilla" puesto que realmente el campo importe no existe como tal en el gestor de BD y no podemos hacer cosas como sumar todos los importes haciendo una agregación, así esto
total_importe=modelo.aggregate(Sum('importe'))
Nos genera un error diciendo que el campo importe no existe.
Sin duda, el soporte para campos calculados es uno de las mejoras del ORM que puede trabajarse.
Fuentes:
http://stackoverflow.com/questions/3690343/django-orm-equivalent-for-this-sql-calculated-field-derived-from-related-table