You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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',
    )

问题原因

  1. 类型不匹配:生成器里i / 10生成的是float类型,但DecimalField的选项值需要是Decimal类型。表单提交后的值会转为Decimal,此时Decimal('0.3')和float(0.3)因类型和精度问题无法匹配,系统判定为无效选项;而0.5这类能被二进制精确表示的浮点数,刚好能在两种类型间匹配成功,所以可以选中。
  2. 生成器复用限制:生成器表达式只能被遍历一次,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 20:55:57