From ca880218d9e6affeae3d0463640baa0a27825bc3 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 26 Nov 2025 10:32:49 -0500 Subject: [PATCH] Validate position count on FrontPort & FrontPortTemplate --- netbox/dcim/models/device_component_templates.py | 15 ++++++++++++++- netbox/dcim/models/device_components.py | 13 +++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/netbox/dcim/models/device_component_templates.py b/netbox/dcim/models/device_component_templates.py index 090ae2c08..1aa3326dc 100644 --- a/netbox/dcim/models/device_component_templates.py +++ b/netbox/dcim/models/device_component_templates.py @@ -585,6 +585,19 @@ class FrontPortTemplate(ModularComponentTemplateModel): verbose_name = _('front port template') verbose_name_plural = _('front port templates') + def clean(self): + super().clean() + + # Check that positions is greater than or equal to the number of associated RearPortTemplates + if not self._state.adding: + mapping_count = self.mappings.count() + if self.positions < mapping_count: + raise ValidationError({ + "positions": _( + "The number of positions cannot be less than the number of mapped rear port templates ({count})" + ).format(count=mapping_count) + }) + def instantiate(self, **kwargs): return self.component_model( name=self.resolve_name(kwargs.get('module')), @@ -638,7 +651,7 @@ class RearPortTemplate(ModularComponentTemplateModel): def clean(self): super().clean() - # Check that positions count is greater than or equal to the number of associated FrontPortTemplates + # Check that positions is greater than or equal to the number of associated FrontPortTemplates if not self._state.adding: mapping_count = self.mappings.count() if self.positions < mapping_count: diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index bc58c1ead..6eefd6ef1 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -1132,6 +1132,19 @@ class FrontPort(ModularComponentModel, CabledObjectModel, TrackingModelMixin): verbose_name = _('front port') verbose_name_plural = _('front ports') + def clean(self): + super().clean() + + # Check that positions is greater than or equal to the number of associated RearPorts + if not self._state.adding: + mapping_count = self.mappings.count() + if self.positions < mapping_count: + raise ValidationError({ + "positions": _( + "The number of positions cannot be less than the number of mapped rear ports ({count})" + ).format(count=mapping_count) + }) + class RearPort(ModularComponentModel, CabledObjectModel, TrackingModelMixin): """