Closes #19945: Create DecimalVar class for custom script input (#19963)

This commit is contained in:
Kyer 2025-07-29 08:49:33 -05:00 committed by GitHub
parent 6b70dea18b
commit 89a94486e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 79 additions and 0 deletions

View File

@ -275,6 +275,15 @@ Stores a numeric integer. Options include:
* `min_value` - Minimum value * `min_value` - Minimum value
* `max_value` - Maximum value * `max_value` - Maximum value
### DecimalVar
Stores a numeric decimal. Options include:
* `min_value` - Minimum value
* `max_value` - Maximum value
* `max_digits` - Maximum number of digits, including decimal places
* `decimal_places` - Number of decimal places
### BooleanVar ### BooleanVar
A true/false flag. This field has no options beyond the defaults listed above. A true/false flag. This field has no options beyond the defaults listed above.

View File

@ -31,6 +31,7 @@ __all__ = (
'DateTimeVar', 'DateTimeVar',
'FileVar', 'FileVar',
'IntegerVar', 'IntegerVar',
'DecimalVar',
'IPAddressVar', 'IPAddressVar',
'IPAddressWithMaskVar', 'IPAddressWithMaskVar',
'IPNetworkVar', 'IPNetworkVar',
@ -135,6 +136,26 @@ class IntegerVar(ScriptVariable):
self.field_attrs['max_value'] = max_value self.field_attrs['max_value'] = max_value
class DecimalVar(ScriptVariable):
"""
Decimal representation. Can enforce minimum/maximum values, maximum digits and decimal places.
"""
form_field = forms.DecimalField
def __init__(self, min_value=None, max_value=None, max_digits=None, decimal_places=None, *args, **kwargs,):
super().__init__(*args, **kwargs)
# Optional constraints
if min_value:
self.field_attrs["min_value"] = min_value
if max_value:
self.field_attrs["max_value"] = max_value
if max_digits:
self.field_attrs["max_digits"] = max_digits
if decimal_places:
self.field_attrs["decimal_places"] = decimal_places
class BooleanVar(ScriptVariable): class BooleanVar(ScriptVariable):
""" """
Boolean representation (true/false). Renders as a checkbox. Boolean representation (true/false). Renders as a checkbox.

View File

@ -1,6 +1,7 @@
import logging import logging
import tempfile import tempfile
from datetime import date, datetime, timezone from datetime import date, datetime, timezone
from decimal import Decimal
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase from django.test import TestCase
@ -138,6 +139,54 @@ class ScriptVariablesTest(TestCase):
self.assertTrue(form.is_valid()) self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data['var1'], data['var1']) self.assertEqual(form.cleaned_data['var1'], data['var1'])
def test_decimalvar(self):
class TestScript(Script):
var1 = DecimalVar(
min_value=-100.500,
max_value=100.500,
max_digits=6,
decimal_places=3,
required=False
)
var2 = DecimalVar(
max_digits=3,
decimal_places=1,
required=False
)
# Validate min_value enforcement
data = {'var1': -100.501}
form = TestScript().as_form(data, None)
self.assertFalse(form.is_valid())
self.assertIn('var1', form.errors)
# Validate max_value enforcement
data = {'var1': 100.501}
form = TestScript().as_form(data, None)
self.assertFalse(form.is_valid())
self.assertIn('var1', form.errors)
# Validate max_digits enforcement
data = {'var2': 123.4}
form = TestScript().as_form(data, None)
self.assertFalse(form.is_valid())
self.assertIn('var2', form.errors)
# Validate decimal_places
data = {'var2': 1.23}
form = TestScript().as_form(data, None)
self.assertFalse(form.is_valid())
self.assertIn('var2', form.errors)
# Validate valid data
data = {'var1': '50.123'}
form = TestScript().as_form(data, None)
self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data['var1'], Decimal(data['var1']))
def test_booleanvar(self): def test_booleanvar(self):
class TestScript(Script): class TestScript(Script):