Django ORM 和 SQLite 中的数学:如果舍入则忽略小数,如果不舍入则结果正确
Posted
技术标签:
【中文标题】Django ORM 和 SQLite 中的数学:如果舍入则忽略小数,如果不舍入则结果正确【英文标题】:Math in Django ORM and SQLite: decimal ignored if round number, correct result if not round 【发布时间】:2022-01-16 10:41:30 【问题描述】:在一个复杂的查询中,我有一个这样的注释:
result.annotate(test=ExpressionWrapper(485.00 / F( 'period_duration' ),
output_field=DecimalField()))
这给了我正确的结果:
Decimal('8.01917989417989E-10')
但是,如果我将 485.00
替换为 485
:
result.annotate(test=ExpressionWrapper( 485 / F( 'period_duration' ),
output_field=DecimalField()))
我明白了:
Decimal('0')
这不是问题,如果不是 485 也来自一个名为“value
”的字段。我的查询如下所示:
result.annotate(test=ExpressionWrapper( F( 'value' ) / F( 'period_duration' ),
output_field=DecimalField()))
Value 是 MoneyField,基本上只是 DecimalField 的精美包装。
我可以强制我的用户始终使用正确的小数(485.00
而不是485
),这本身就是不好的设计,但是......即使那样,如果数据库值为485.00
,Django 的行为就好像它是 485
并因此在进行浮点数学运算时返回 0
。
我尝试将Cast
ing 值改为DecimalField
,但无济于事。
result.annotate( res=ExpressionWrapper(
Cast('value', output_field=DecimalField()) / F( 'period_duration' ),
output_field=DecimalField() )).last().res
结果总是:
Decimal('0')
而不是正确的:
Decimal('8.01917989417989E-10')
如何强制 Django 始终使用浮点数学?
附言period_duration
是 604800000000
,如果有帮助的话。
【问题讨论】:
您应该查看(并编辑您的问题)此处生成的实际 SQL 查询。print(queryset.query)
【参考方案1】:
你确定F( 'value' )
给你一个号码吗?
MoneyField 将您的属性 value 存储在两列中,因此 F( 'value' )
可能不是您所期望的。
不妨试试F( 'value_amount' )
。
【讨论】:
是的,它给出了一个数字。 value_amount 返回错误。 value.amount 仅在 Python 中,在数据库级别只有 value 和 value_currency。以上是关于Django ORM 和 SQLite 中的数学:如果舍入则忽略小数,如果不舍入则结果正确的主要内容,如果未能解决你的问题,请参考以下文章