Django科学记数法输入验证

时间:2017-12-14 17:31:49

标签: python django

我的模型上有以下字段:

class Range(models.Model):
    optimal_low = models.DecimalField(max_digits=30, decimal_places=8)
    optimal_high = models.DecimalField(max_digits=30, decimal_places=8)

以下是我如何将它们带入表单中(因为表单的主要对象不是此模型,我只需要字段,并且不想复制max_digits和decimal_places

class ReadingMappingForm(forms.ModelForm):
    optimal_low = Range._meta.get_field('optimal_low').formfield()
    optimal_high = Range._meta.get_field('optimal_high').formfield()

似乎django允许以开箱即用的科学记数法输入小数,但是有一个小于某个阈值的小故障。

在表单中,如果我输入 1.5E9 ,它可以正常工作,并将值保存为 1500000000.00000000 (此处为online scientific notation calculator

但是,如果我输入 1.5E10 ,则说:

  

确保小数位数不超过8个。

哪个错了,因为我没有添加任何小数位。事实上,如果我以正常表示法输入 1.5E10 ,即使添加了8位小数,即 15000000000.00000000 ,它也能正常工作。

所以我觉得有些事情在幕后工作不正确......

修改

我在控制台中测试了该字段,并在那里出现错误:

from django.forms import DecimalField
>>> f = DecimalField(max_digits=30, decimal_places=8)
>>> f.clean('1.5E9')
Decimal('1.5E+9')
>>> f.clean('1.5E10')
Traceback (most recent call last):
  File "myproject/env/lib/python3.5/site-packages/django/core/management/commands/shell.py", line 69, in handle
    self.run_shell(shell=options['interface'])
  File "myproject/env/lib/python3.5/site-packages/django/core/management/commands/shell.py", line 61, in run_shell
    raise ImportError
ImportError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "myproject/env/lib/python3.5/site-packages/django/forms/fields.py", line 168, in clean
    self.run_validators(value)
  File "myproject/env/lib/python3.5/site-packages/django/forms/fields.py", line 157, in run_validators
    raise ValidationError(errors)
django.core.exceptions.ValidationError: ['Ensure that there are no more than 8 decimal places.']

2 个答案:

答案 0 :(得分:1)

它似乎是DecimalValidator中的错误,具有以下解释

您声明的数字 1.5E10 被解析为具有属性_int '15'_exp 9的对象

在DecimalValidator __call__方法中,小数位数计算为

decimals = abs(exponent)

除此之外还会触发以下

if self.decimal_places is not None and decimals > self.decimal_places:
    raise ValidationError(
        self.messages['max_decimal_places'],
        code='max_decimal_places',
        params={'max': self.decimal_places},
    )

似乎修复以下内容就像是

if exponent < 0:
     decimal = abs(exponent)
else:
     decimal = 0

修复版本2.0如下所示

# If the absolute value of the negative exponent is larger than the
# number of digits, then it's the same as the number of digits,
# because it'll consume all of the digits in digit_tuple and then
# add abs(exponent) - len(digit_tuple) leading zeros after the
# decimal point.
if abs(exponent) > len(digit_tuple):
    digits = decimals = abs(exponent)
else:
    digits = len(digit_tuple)
    decimals = abs(exponent)

答案 1 :(得分:0)

这是一个已知的bug,它是固定的,但据我所知,只在django 2.0中。