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
* `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
A true/false flag. This field has no options beyond the defaults listed above.

View File

@ -31,6 +31,7 @@ __all__ = (
'DateTimeVar',
'FileVar',
'IntegerVar',
'DecimalVar',
'IPAddressVar',
'IPAddressWithMaskVar',
'IPNetworkVar',
@ -135,6 +136,26 @@ class IntegerVar(ScriptVariable):
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):
"""
Boolean representation (true/false). Renders as a checkbox.

View File

@ -1,6 +1,7 @@
import logging
import tempfile
from datetime import date, datetime, timezone
from decimal import Decimal
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
@ -138,6 +139,54 @@ class ScriptVariablesTest(TestCase):
self.assertTrue(form.is_valid())
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):
class TestScript(Script):