【问题标题】:Django scientific notation input validationDjango 科学记数法输入验证
【发布时间】:2018-05-28 21:08:36
【问题描述】:

我的模型上有以下字段:

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.']

【问题讨论】:

    标签: python django


    【解决方案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)
    

    【讨论】:

    • 谢谢,也请看我的回复,这个错误已修复,但似乎只适用于 Django 2.0
    【解决方案2】:

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

    【讨论】:

    • 我也找到了所有这些。我会接受我自己的答案,因为它在技术上是正确的,但是你在你的工作中投入了更多的精力,所以你得到了重点:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-09
    相关资源
    最近更新 更多