Django DecimalField设min_value=0.20时输入0.20报校验错误
问题产生原因
核心原因是浮点数二进制存储的精度丢失问题:
- 字段参数中传入的
min_value=0.20、max_value=20.00都是Python原生float类型,十进制小数0.2无法用二进制浮点数精确表示,实际存储的是略大于0.2的近似值(双精度float下精确展开约为0.2000000000000000111)。 - Django的
DecimalField处理表单输入时,会把用户输入的0.20转换为精确的Decimal('0.20')类型,校验阶段拿这个精确值和传入的float类型最小值做比较,就会出现精确的0.20小于float近似值的情况,最终触发校验不通过的错误。
修复方案
所有涉及数值边界的参数,统一使用decimal.Decimal类型传入,注意构造Decimal实例时要传入字符串形式的数值,不要直接传入float字面量,避免精度问题残留。
- 导入Decimal类:
from decimal import Decimal
- 调整字段定义代码:
forms.DecimalField( min_value=Decimal('0.20'), max_value=Decimal('20.00'), max_digits=4, decimal_places=2, initial=Decimal('1') )
修改后边界值均为精确的十进制值,和用户输入转换后的Decimal值比较时不会出现精度偏差,输入0.20即可正常通过校验。
注意:不要使用
Decimal(0.20)的写法,这种写法会先将不精确的float值传入Decimal构造函数,精度问题依然存在。
内容的提问来源于stack exchange,提问作者Marian
相关产品推荐
相关产品推荐

