Django DecimalField配置Choices后表单更新部分值为空如何解决
问题根源
核心问题是choices的键值类型和DecimalField实际存储的类型不匹配:
- 自定义的
decimal_range返回float类型作为choices的第一个元素 DecimalField从数据库读取出来的是Decimal类型对象- 两者做等值判断时,
7.0 == Decimal('7.00')这类场景会因为浮点精度问题返回False,只有浮点表示完全一致的小数(比如带0.25/0.75后缀的)才能匹配成功,因此表单更新时对应选项无法选中。
修复步骤
1. 修正decimal_range函数,全程使用Decimal类型运算和返回
不要在生成序列时转为float,避免精度损失:
from decimal import Decimal, getcontext def decimal_range(A, B, X): """ 生成从A开始到B结束,步长为X的Decimal序列 """ getcontext().prec = 5 # 入参统一转字符串后再转Decimal,避免传入float/int导致精度问题 current = Decimal(str(A)) end = Decimal(str(B)) step = Decimal(str(X)) while current <= end: yield current current += step
2. 重新生成CHOICES
此时生成的choices第一个元素为Decimal类型,和字段存储类型完全匹配:
S_CHOICES = tuple((i, f"{i:.2f}") for i in decimal_range(-20, 20, 0.25))
注:如果需要包含边界值20,不需要额外传20.25作为结束值,步长0.25的情况下传20作为结束值即可刚好覆盖到20.00。
3. (可选)修正已有脏数据
如果数据库中已经存在格式异常的存量数据,可以运行脚本统一格式化:
# 进入Django shell执行,替换为你自己的模型导入路径 from yourapp.models import YourModel from decimal import Decimal for obj in YourModel.objects.all(): if obj.arrs is not None: obj.arrs = Decimal(f"{obj.arrs:.2f}") obj.save(update_fields=['arrs'])
内容的提问来源于stack exchange,提问作者eng.ragy
相关产品推荐
相关产品推荐

