Django后台仅可选择0.5倍数数值?模型配置问题排查
Django模型PH值多选只能选0.5倍数的问题排查
问题描述
我在Django中创建了一个模型,提供0到14之间步长为0.1的数值多选选项。在后台管理面板中能看到所有选项,但仅能选择0.5的倍数,选择其他值会触发报错:Select a valid choice. 0.3 is not one of the available choices.
模型代码
class SoilPh(models.Model): SOIL_PH_CHOICES = ( (i / 10, str(i / 10)) for i in range(MAX_PH_LEVEL * 10 + 1) ) name = models.DecimalField( max_digits=2, decimal_places=1, validators=[ MinValueValidator(0, '0'), MaxValueValidator(MAX_PH_LEVEL, f'{MAX_PH_LEVEL}') ], choices=SOIL_PH_CHOICES, unique=True, null=True, ) class Deciduous(Plant): soil_ph = models.ManyToManyField( SoilPh, related_name='soil_ph', )
问题原因
- 类型不匹配:生成器里
i / 10生成的是float类型,但DecimalField的选项值需要是Decimal类型。表单提交后的值会转为Decimal,此时Decimal('0.3')和float(0.3)因类型和精度问题无法匹配,系统判定为无效选项;而0.5这类能被二进制精确表示的浮点数,刚好能在两种类型间匹配成功,所以可以选中。 - 生成器复用限制:生成器表达式只能被遍历一次,Django在渲染表单和验证时会多次访问选项列表,第二次访问时生成器已经耗尽,也会导致验证时无完整选项可用。
解决方法
将生成器表达式改为列表推导式,同时把选项值转为Decimal类型,和字段类型保持一致:
from decimal import Decimal class SoilPh(models.Model): # 改用列表推导式,并生成Decimal类型的选项值 SOIL_PH_CHOICES = [ (Decimal(i) / Decimal(10), str(Decimal(i)/Decimal(10))) for i in range(MAX_PH_LEVEL * 10 + 1) ] name = models.DecimalField( max_digits=2, decimal_places=1, validators=[ MinValueValidator(0, '0'), MaxValueValidator(MAX_PH_LEVEL, f'{MAX_PH_LEVEL}') ], choices=SOIL_PH_CHOICES, unique=True, null=True, )
这样既保证了选项列表可以被多次访问,又让选项值的类型和DecimalField完全匹配,所有步长为0.1的数值都能正常被选中和验证。
内容的提问来源于stack exchange,提问作者Inozem
相关产品推荐
相关产品推荐

