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

我尝试将Casting 值改为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_duration604800000000,如果有帮助的话。

【问题讨论】:

您应该查看(并编辑您的问题)此处生成的实际 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 中的数学:如果舍入则忽略小数,如果不舍入则结果正确的主要内容,如果未能解决你的问题,请参考以下文章

django中的ORM系统

Django ORM 数据库设置和读写分离

Django ORM 数据库设置和读写分离

django之数据库orm

与ORM django和sqlite3数据库相关的问题

Django基础(ORM)