Fixes #8201: Custom integer fields should allow negative integers as minimum/maximum values

This commit is contained in:
jeremystretch 2022-01-03 10:07:19 -05:00
parent 7b0dff88ae
commit 05d4176d34
4 changed files with 73 additions and 32 deletions

View File

@ -13,6 +13,7 @@
* [#8187](https://github.com/netbox-community/netbox/issues/8187) - Fix rendering of tags column in object tables * [#8187](https://github.com/netbox-community/netbox/issues/8187) - Fix rendering of tags column in object tables
* [#8191](https://github.com/netbox-community/netbox/issues/8191) - Fix return URL when adding IP addresses to VM interfaces * [#8191](https://github.com/netbox-community/netbox/issues/8191) - Fix return URL when adding IP addresses to VM interfaces
* [#8196](https://github.com/netbox-community/netbox/issues/8196) - Fix IndexError exception when viewing large IPv6 prefixes in UI * [#8196](https://github.com/netbox-community/netbox/issues/8196) - Fix IndexError exception when viewing large IPv6 prefixes in UI
* [#8201](https://github.com/netbox-community/netbox/issues/8201) - Custom integer fields should allow negative integers as minimum/maximum values
--- ---

View File

@ -0,0 +1,21 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('extras', '0066_customfield_name_validation'),
]
operations = [
migrations.AlterField(
model_name='customfield',
name='validation_maximum',
field=models.IntegerField(blank=True, null=True),
),
migrations.AlterField(
model_name='customfield',
name='validation_minimum',
field=models.IntegerField(blank=True, null=True),
),
]

View File

@ -96,13 +96,13 @@ class CustomField(ChangeLoggedModel):
default=100, default=100,
help_text='Fields with higher weights appear lower in a form.' help_text='Fields with higher weights appear lower in a form.'
) )
validation_minimum = models.PositiveIntegerField( validation_minimum = models.IntegerField(
blank=True, blank=True,
null=True, null=True,
verbose_name='Minimum value', verbose_name='Minimum value',
help_text='Minimum allowed value (for numeric fields)' help_text='Minimum allowed value (for numeric fields)'
) )
validation_maximum = models.PositiveIntegerField( validation_maximum = models.IntegerField(
blank=True, blank=True,
null=True, null=True,
verbose_name='Maximum value', verbose_name='Maximum value',

View File

@ -25,49 +25,68 @@ class CustomFieldTest(TestCase):
def test_simple_fields(self): def test_simple_fields(self):
DATA = ( DATA = (
{ {
'field_type': CustomFieldTypeChoices.TYPE_TEXT, 'field': {
'field_value': 'Foobar!', 'type': CustomFieldTypeChoices.TYPE_TEXT,
'empty_value': '', },
'value': 'Foobar!',
}, },
{ {
'field_type': CustomFieldTypeChoices.TYPE_LONGTEXT, 'field': {
'field_value': 'Text with **Markdown**', 'type': CustomFieldTypeChoices.TYPE_LONGTEXT,
'empty_value': '', },
'value': 'Text with **Markdown**',
}, },
{ {
'field_type': CustomFieldTypeChoices.TYPE_INTEGER, 'field': {
'field_value': 0, 'type': CustomFieldTypeChoices.TYPE_INTEGER,
'empty_value': None, },
'value': 0,
}, },
{ {
'field_type': CustomFieldTypeChoices.TYPE_INTEGER, 'field': {
'field_value': 42, 'type': CustomFieldTypeChoices.TYPE_INTEGER,
'empty_value': None, 'validation_minimum': 1,
'validation_maximum': 100,
},
'value': 42,
}, },
{ {
'field_type': CustomFieldTypeChoices.TYPE_BOOLEAN, 'field': {
'field_value': True, 'type': CustomFieldTypeChoices.TYPE_INTEGER,
'empty_value': None, 'validation_minimum': -100,
'validation_maximum': -1,
},
'value': -42,
}, },
{ {
'field_type': CustomFieldTypeChoices.TYPE_BOOLEAN, 'field': {
'field_value': False, 'type': CustomFieldTypeChoices.TYPE_BOOLEAN,
'empty_value': None, },
'value': True,
}, },
{ {
'field_type': CustomFieldTypeChoices.TYPE_DATE, 'field': {
'field_value': '2016-06-23', 'type': CustomFieldTypeChoices.TYPE_BOOLEAN,
'empty_value': None, },
'value': False,
}, },
{ {
'field_type': CustomFieldTypeChoices.TYPE_URL, 'field': {
'field_value': 'http://example.com/', 'type': CustomFieldTypeChoices.TYPE_DATE,
'empty_value': '', },
'value': '2016-06-23',
}, },
{ {
'field_type': CustomFieldTypeChoices.TYPE_JSON, 'field': {
'field_value': '{"foo": 1, "bar": 2}', 'type': CustomFieldTypeChoices.TYPE_URL,
'empty_value': 'null', },
'value': 'http://example.com/',
},
{
'field': {
'type': CustomFieldTypeChoices.TYPE_JSON,
},
'value': '{"foo": 1, "bar": 2}',
}, },
) )
@ -76,7 +95,7 @@ class CustomFieldTest(TestCase):
for data in DATA: for data in DATA:
# Create a custom field # Create a custom field
cf = CustomField(type=data['field_type'], name='my_field', required=False) cf = CustomField(name='my_field', required=False, **data['field'])
cf.save() cf.save()
cf.content_types.set([obj_type]) cf.content_types.set([obj_type])
@ -85,12 +104,12 @@ class CustomFieldTest(TestCase):
self.assertIsNone(site.custom_field_data[cf.name]) self.assertIsNone(site.custom_field_data[cf.name])
# Assign a value to the first Site # Assign a value to the first Site
site.custom_field_data[cf.name] = data['field_value'] site.custom_field_data[cf.name] = data['value']
site.save() site.save()
# Retrieve the stored value # Retrieve the stored value
site.refresh_from_db() site.refresh_from_db()
self.assertEqual(site.custom_field_data[cf.name], data['field_value']) self.assertEqual(site.custom_field_data[cf.name], data['value'])
# Delete the stored value # Delete the stored value
site.custom_field_data.pop(cf.name) site.custom_field_data.pop(cf.name)