From c785b0409bb0fbe47d96fee22386f6024b8cddfb Mon Sep 17 00:00:00 2001 From: Jason Novinger Date: Fri, 5 Sep 2025 07:27:20 -0500 Subject: [PATCH 1/3] Make CachedScopeMixin.clean() raise non-field ValidationError --- netbox/dcim/models/mixins.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/netbox/dcim/models/mixins.py b/netbox/dcim/models/mixins.py index e9484264c3a..8bcf5dc6096 100644 --- a/netbox/dcim/models/mixins.py +++ b/netbox/dcim/models/mixins.py @@ -87,11 +87,9 @@ class Meta: def clean(self): if self.scope_type and not (self.scope or self.scope_id): scope_type = self.scope_type.model_class() - raise ValidationError({ - 'scope': _( - "Please select a {scope_type}." - ).format(scope_type=scope_type._meta.model_name) - }) + raise ValidationError( + _("Please select a {scope_type}.").format(scope_type=scope_type._meta.model_name) + ) super().clean() def save(self, *args, **kwargs): From 126e45c1f2eea5b37bd17465580f6694977bc16e Mon Sep 17 00:00:00 2001 From: Jason Novinger Date: Fri, 5 Sep 2025 07:52:56 -0500 Subject: [PATCH 2/3] Enforce field-level ValidationError in ScopedImportForm/ScopedForm.clean() --- netbox/dcim/forms/mixins.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/netbox/dcim/forms/mixins.py b/netbox/dcim/forms/mixins.py index 5a57e33648f..64b5beb473b 100644 --- a/netbox/dcim/forms/mixins.py +++ b/netbox/dcim/forms/mixins.py @@ -1,6 +1,6 @@ from django import forms from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import ObjectDoesNotExist +from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.utils.translation import gettext_lazy as _ from dcim.constants import LOCATION_SCOPE_TYPES @@ -48,8 +48,17 @@ def __init__(self, *args, **kwargs): def clean(self): super().clean() + scope = self.cleaned_data.get('scope') + scope_type = self.cleaned_data.get('scope_type') + if scope_type and not scope: + raise ValidationError({ + 'scope_id': _( + "Please select a {scope_type}." + ).format(scope_type=scope_type.model_class()._meta.model_name) + }) + # Assign the selected scope (if any) - self.instance.scope = self.cleaned_data.get('scope') + self.instance.scope = scope def _set_scoped_values(self): if scope_type_id := get_field_value(self, 'scope_type'): @@ -107,3 +116,15 @@ class ScopedImportForm(forms.Form): required=False, label=_('Scope type (app & model)') ) + + def clean(self): + super().clean() + + scope_id = self.cleaned_data.get('scope_id') + scope_type = self.cleaned_data.get('scope_type') + if scope_type and not scope_id: + raise ValidationError({ + 'scope_id': _( + "Please select a {scope_type}." + ).format(scope_type=scope_type.model_class()._meta.model_name) + }) From 4ee304468e66346efa1725aec33a7e5927a19076 Mon Sep 17 00:00:00 2001 From: Jason Novinger Date: Fri, 5 Sep 2025 09:43:46 -0500 Subject: [PATCH 3/3] Fix wrong field used in ValidationError --- netbox/dcim/forms/mixins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/dcim/forms/mixins.py b/netbox/dcim/forms/mixins.py index 64b5beb473b..96eb8a56b9d 100644 --- a/netbox/dcim/forms/mixins.py +++ b/netbox/dcim/forms/mixins.py @@ -52,7 +52,7 @@ def clean(self): scope_type = self.cleaned_data.get('scope_type') if scope_type and not scope: raise ValidationError({ - 'scope_id': _( + 'scope': _( "Please select a {scope_type}." ).format(scope_type=scope_type.model_class()._meta.model_name) })