Matemáticas en Django ORM y SQLite: decimal ignorado si el número es redondo, resultado correcto si no es redondo.
En una consulta compleja, tengo una anotación como esta:
result.annotate(test=ExpressionWrapper(485.00 / F('period_duration'), output_field=DecimalField()))
Esto me devuelve el resultado correcto:
Decimal('8.01917989417989E-10')
Sin embargo, si reemplazo 485.00
con 485
:
result.annotate(test=ExpressionWrapper(485 / F('period_duration'), output_field=DecimalField()))
Obtengo:
Decimal('0')
Esto no sería un problema si no fuera porque 485 también proviene de un campo llamado “value”. Mi consulta se ve así:
result.annotate(test=ExpressionWrapper(F('value') / F('period_duration'), output_field=DecimalField()))
“Value” es un MoneyField, básicamente un envoltorio elegante alrededor de DecimalField.
Puedo obligar a mis usuarios a siempre usar decimales adecuados (485.00
en lugar de 485
), lo cual sería un diseño deficiente, pero… incluso entonces, si el valor en la base de datos es 485.00
, Django se comporta como si fuera 485
y devuelve 0
al realizar una operación de punto flotante.
He intentado realizar un Cast
del valor a un DecimalField
, sin éxito:
result.annotate(res=ExpressionWrapper(
Cast('value', output_field=DecimalField()) / F('period_duration'), output_field=DecimalField()
)).last().res
El resultado siempre es:
Decimal('0')
En lugar del correcto:
Decimal('8.01917989417989E-10')
¿Cómo puedo obligar a Django a siempre usar operaciones de punto flotante?
PD: period_duration
es 604800000000
, si eso ayuda en algo.
davy.ai
El problema es que cuando el valor en la expresión es un número entero en lugar de decimal, Django realiza una división entera en lugar de una división de punto flotante. Para forzar a Django a realizar una división de punto flotante, puedes usar el
FloatField
en lugar deDecimalField
en el argumentooutput_field
deExpressionWrapper
de la siguiente manera:Esto debería darte el resultado correcto de punto flotante incluso si el valor en el
MoneyField
es un entero.