简体   繁体   中英

Django scientific notation input validation

I have the following fields on my model:

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

And here's how I bring them into the form (because the form's primary object is not this model, I just need the fields, and don't want to duplicate the max_digits and decimal_places.

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

It seems django allows entering of decimals in scientific notation out of the box, but there's a glitch above a certain threshold.

In the form, if I input 1.5E9 it works fine, and the value gets saved as 1500000000.00000000 (Here's an online scientific notation calculator ).

However if I input 1.5E10 it says:

Ensure that there are no more than 8 decimal places.

Which is wrong, because I'm not adding any decimal places. In fact, if I enter 1.5E10 in normal notation, even with the 8 decimal places added, ie 15000000000.00000000 it works fine.

So I think something is not working correctly under the hood...

EDIT

I tested the field in the console, and it errors there:

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

It does seem to be bug in DecimalValidator with the following explanation

Number that you stated 1.5E10 is parsed as object with properties _int '15' and _exp 9

In DecimalValidator __call__ method number of decimals is calculated as

decimals = abs(exponent)

which than furthermore triggers the following

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

Seems that fix for following would be something like

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

Fix for version 2.0 looks like following

# 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 中存在。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM