diff --git a/docs/models/extras/customfield.md b/docs/models/extras/customfield.md index 0932791e7..e3462a6a7 100644 --- a/docs/models/extras/customfield.md +++ b/docs/models/extras/customfield.md @@ -20,7 +20,7 @@ Custom fields may be created by navigating to Customization > Custom Fields. Net * Selection: A selection of one of several pre-defined custom choices * Multiple selection: A selection field which supports the assignment of multiple values -Each custom field must have a name; this should be a simple database-friendly string, e.g. `tps_report`. You may also assign a corresponding human-friendly label (e.g. "TPS report"); the label will be displayed on web forms. A weight is also required: Higher-weight fields will be ordered lower within a form. (The default weight is 100.) If a description is provided, it will appear beneath the field in a form. +Each custom field must have a name. This should be a simple database-friendly string (e.g. `tps_report`) and may contain only alphanumeric characters and underscores. You may also assign a corresponding human-friendly label (e.g. "TPS report"); the label will be displayed on web forms. A weight is also required: Higher-weight fields will be ordered lower within a form. (The default weight is 100.) If a description is provided, it will appear beneath the field in a form. Marking a field as required will force the user to provide a value for the field when creating a new object or when saving an existing object. A default value for the field may also be provided. Use "true" or "false" for boolean fields, or the exact value of a choice for selection fields. diff --git a/docs/release-notes/version-3.1.md b/docs/release-notes/version-3.1.md index 92af0e1cc..7e2305e6f 100644 --- a/docs/release-notes/version-3.1.md +++ b/docs/release-notes/version-3.1.md @@ -12,6 +12,7 @@ * [#8009](https://github.com/netbox-community/netbox/issues/8009) - Validate IP addresses for uniqueness when creating an FHRP group * [#8010](https://github.com/netbox-community/netbox/issues/8010) - Allow filtering devices by multiple serial numbers * [#8019](https://github.com/netbox-community/netbox/issues/8019) - Exclude metrics endpoint when `LOGIN_REQUIRED` is true +* [#8030](https://github.com/netbox-community/netbox/issues/8030) - Validate custom field names * [#8033](https://github.com/netbox-community/netbox/issues/8033) - Fix display of zero values for custom integer fields in tables --- diff --git a/netbox/extras/migrations/0066_customfield_name_validation.py b/netbox/extras/migrations/0066_customfield_name_validation.py new file mode 100644 index 000000000..7a768c10c --- /dev/null +++ b/netbox/extras/migrations/0066_customfield_name_validation.py @@ -0,0 +1,18 @@ +import django.core.validators +from django.db import migrations, models +import re + + +class Migration(migrations.Migration): + + dependencies = [ + ('extras', '0065_imageattachment_change_logging'), + ] + + operations = [ + migrations.AlterField( + model_name='customfield', + name='name', + field=models.CharField(max_length=50, unique=True, validators=[django.core.validators.RegexValidator(flags=re.RegexFlag['IGNORECASE'], message='Only alphanumeric characters and underscores are allowed.', regex='^[a-z0-9_]+$')]), + ), + ] diff --git a/netbox/extras/models/customfields.py b/netbox/extras/models/customfields.py index 1c511a852..713ef6c93 100644 --- a/netbox/extras/models/customfields.py +++ b/netbox/extras/models/customfields.py @@ -22,6 +22,12 @@ from utilities.querysets import RestrictedQuerySet from utilities.validators import validate_regex +__all__ = ( + 'CustomField', + 'CustomFieldManager', +) + + class CustomFieldManager(models.Manager.from_queryset(RestrictedQuerySet)): use_in_migrations = True @@ -49,7 +55,14 @@ class CustomField(ChangeLoggedModel): name = models.CharField( max_length=50, unique=True, - help_text='Internal field name' + help_text='Internal field name', + validators=( + RegexValidator( + regex=r'^[a-z0-9_]+$', + message="Only alphanumeric characters and underscores are allowed.", + flags=re.IGNORECASE + ), + ) ) label = models.CharField( max_length=50,