From 836ddbf49dd0ae1f606372bb3601eb52594a5672 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 26 Nov 2025 14:11:08 -0500 Subject: [PATCH] Add FKs from PortMapping & PortTemplateMapping to their parent models --- netbox/dcim/forms/mixins.py | 24 +- netbox/dcim/forms/model_forms.py | 10 +- netbox/dcim/migrations/0222_port_mappings.py | 31 ++ netbox/dcim/models/base.py | 2 + .../dcim/models/device_component_templates.py | 20 + netbox/dcim/models/device_components.py | 10 + netbox/dcim/tests/test_api.py | 44 +- netbox/dcim/tests/test_cablepaths.py | 422 +++++++++++++++--- netbox/dcim/tests/test_cablepaths2.py | 66 ++- netbox/dcim/tests/test_filtersets.py | 32 +- netbox/dcim/tests/test_models.py | 9 +- netbox/dcim/tests/test_views.py | 30 +- netbox/dcim/utils.py | 7 +- 13 files changed, 564 insertions(+), 143 deletions(-) diff --git a/netbox/dcim/forms/mixins.py b/netbox/dcim/forms/mixins.py index 0497cd1ed..98d2117b6 100644 --- a/netbox/dcim/forms/mixins.py +++ b/netbox/dcim/forms/mixins.py @@ -4,7 +4,7 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.utils.translation import gettext_lazy as _ from dcim.constants import LOCATION_SCOPE_TYPES -from dcim.models import PortMapping, Site +from dcim.models import PortMapping, PortTemplateMapping, Site from utilities.forms import get_field_value from utilities.forms.fields import ( ContentTypeChoiceField, CSVContentTypeField, DynamicModelChoiceField, @@ -161,14 +161,24 @@ class FrontPortFormMixin(forms.Form): # Create new rear port mappings mappings = [] + if self.port_mapping_model is PortTemplateMapping: + params = { + 'device_type_id': self.instance.device_type_id, + 'module_type_id': self.instance.module_type_id, + } + else: + params = { + 'device_id': self.instance.device_id, + } for i, rp_position in enumerate(self.cleaned_data['rear_ports'], start=1): rear_port_id, rear_port_position = rp_position.split(':') mappings.append( - self.port_mapping_model( - front_port_id=self.instance.pk, - front_port_position=i, - rear_port_id=rear_port_id, - rear_port_position=rear_port_position, - ) + self.port_mapping_model(**{ + **params, + 'front_port_id': self.instance.pk, + 'front_port_position': i, + 'rear_port_id': rear_port_id, + 'rear_port_position': rear_port_position, + }) ) self.port_mapping_model.objects.bulk_create(mappings) diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index e21cad38e..709ecdfe0 100644 --- a/netbox/dcim/forms/model_forms.py +++ b/netbox/dcim/forms/model_forms.py @@ -1158,10 +1158,8 @@ class FrontPortTemplateForm(FrontPortFormMixin, ModularComponentTemplateForm): those assigned to the specified instance. """ occupied_rear_port_positions = [ - f'{assignment.rear_port_id}:{assignment.rear_port_position}' - for assignment in PortTemplateMapping.objects.filter( - front_port__device_type=device_type - ).exclude(front_port=front_port.pk) + f'{mapping.rear_port_id}:{mapping.rear_port_position}' + for mapping in device_type.port_mappings.exclude(front_port=front_port.pk) ] choices = [] @@ -1652,8 +1650,8 @@ class FrontPortForm(FrontPortFormMixin, ModularDeviceComponentForm): assigned to the specified instance. """ occupied_rear_port_positions = [ - f'{assignment.rear_port_id}:{assignment.rear_port_position}' - for assignment in PortMapping.objects.filter(front_port__device=device).exclude(front_port=front_port.pk) + f'{mapping.rear_port_id}:{mapping.rear_port_position}' + for mapping in device.port_mappings.exclude(front_port=front_port.pk) ] choices = [] diff --git a/netbox/dcim/migrations/0222_port_mappings.py b/netbox/dcim/migrations/0222_port_mappings.py index 7978ca288..a163ae18d 100644 --- a/netbox/dcim/migrations/0222_port_mappings.py +++ b/netbox/dcim/migrations/0222_port_mappings.py @@ -23,6 +23,8 @@ def populate_port_template_mappings(apps, schema_editor): def generate_copies(): for front_port in front_ports: yield PortTemplateMapping( + device_type_id=front_port.device_type_id, + module_type_id=front_port.module_type_id, front_port_id=front_port.pk, front_port_position=1, rear_port_id=front_port.rear_port_id, @@ -43,6 +45,7 @@ def populate_port_mappings(apps, schema_editor): def generate_copies(): for front_port in front_ports: yield PortMapping( + device_id=front_port.device_id, front_port_id=front_port.pk, front_port_position=1, rear_port_id=front_port.rear_port_id, @@ -85,6 +88,26 @@ class Migration(migrations.Migration): ] ) ), + ( + 'device_type', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to='dcim.devicetype', + related_name='port_mappings', + blank=True, + null=True + ) + ), + ( + 'module_type', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to='dcim.moduletype', + related_name='port_mappings', + blank=True, + null=True + ) + ), ( 'front_port', models.ForeignKey( @@ -143,6 +166,14 @@ class Migration(migrations.Migration): ] ), ), + ( + 'device', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to='dcim.device', + related_name='port_mappings' + ) + ), ( 'front_port', models.ForeignKey( diff --git a/netbox/dcim/models/base.py b/netbox/dcim/models/base.py index f75ddfefa..f8021d4db 100644 --- a/netbox/dcim/models/base.py +++ b/netbox/dcim/models/base.py @@ -29,6 +29,8 @@ class PortMappingBase(models.Model): ), ) + _netbox_private = True + class Meta: abstract = True constraints = ( diff --git a/netbox/dcim/models/device_component_templates.py b/netbox/dcim/models/device_component_templates.py index 1aa3326dc..16e281523 100644 --- a/netbox/dcim/models/device_component_templates.py +++ b/netbox/dcim/models/device_component_templates.py @@ -524,6 +524,20 @@ class PortTemplateMapping(PortMappingBase): """ Maps a FrontPortTemplate & position to a RearPortTemplate & position. """ + device_type = models.ForeignKey( + to='dcim.DeviceType', + on_delete=models.CASCADE, + related_name='port_mappings', + blank=True, + null=True, + ) + module_type = models.ForeignKey( + to='dcim.ModuleType', + on_delete=models.CASCADE, + related_name='port_mappings', + blank=True, + null=True, + ) front_port = models.ForeignKey( to='dcim.FrontPortTemplate', on_delete=models.CASCADE, @@ -546,6 +560,12 @@ class PortTemplateMapping(PortMappingBase): ) }) + def save(self, *args, **kwargs): + # Associate the mapping with the parent DeviceType/ModuleType + self.device_type = self.front_port.device_type + self.module_type = self.front_port.module_type + super().save(*args, **kwargs) + class FrontPortTemplate(ModularComponentTemplateModel): """ diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index 6eefd6ef1..b629813de 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -1075,6 +1075,11 @@ class PortMapping(PortMappingBase): """ Maps a FrontPort & position to a RearPort & position. """ + device = models.ForeignKey( + to='dcim.Device', + on_delete=models.CASCADE, + related_name='port_mappings', + ) front_port = models.ForeignKey( to='dcim.FrontPort', on_delete=models.CASCADE, @@ -1097,6 +1102,11 @@ class PortMapping(PortMappingBase): ) }) + def save(self, *args, **kwargs): + # Associate the mapping with the parent Device + self.device = self.front_port.device + super().save(*args, **kwargs) + class FrontPort(ModularComponentModel, CabledObjectModel, TrackingModelMixin): """ diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index 7f17b7683..419bac20f 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -984,9 +984,21 @@ class FrontPortTemplateTest(APIViewTestCases.APIViewTestCase): ) FrontPortTemplate.objects.bulk_create(front_port_templates) PortTemplateMapping.objects.bulk_create([ - PortTemplateMapping(front_port=front_port_templates[0], rear_port=rear_port_templates[0]), - PortTemplateMapping(front_port=front_port_templates[1], rear_port=rear_port_templates[1]), - PortTemplateMapping(front_port=front_port_templates[2], rear_port=rear_port_templates[2]), + PortTemplateMapping( + device_type=devicetype, + front_port=front_port_templates[0], + rear_port=rear_port_templates[0], + ), + PortTemplateMapping( + device_type=devicetype, + front_port=front_port_templates[1], + rear_port=rear_port_templates[1], + ), + PortTemplateMapping( + module_type=moduletype, + front_port=front_port_templates[2], + rear_port=rear_port_templates[2], + ), ]) cls.create_data = [ @@ -1062,9 +1074,21 @@ class RearPortTemplateTest(APIViewTestCases.APIViewTestCase): ) RearPortTemplate.objects.bulk_create(rear_port_templates) PortTemplateMapping.objects.bulk_create([ - PortTemplateMapping(front_port=front_port_templates[0], rear_port=rear_port_templates[0]), - PortTemplateMapping(front_port=front_port_templates[1], rear_port=rear_port_templates[1]), - PortTemplateMapping(front_port=front_port_templates[2], rear_port=rear_port_templates[2]), + PortTemplateMapping( + device_type=devicetype, + front_port=front_port_templates[0], + rear_port=rear_port_templates[0], + ), + PortTemplateMapping( + device_type=devicetype, + front_port=front_port_templates[1], + rear_port=rear_port_templates[1], + ), + PortTemplateMapping( + module_type=moduletype, + front_port=front_port_templates[2], + rear_port=rear_port_templates[2], + ), ]) cls.create_data = [ @@ -2041,9 +2065,9 @@ class FrontPortTest(APIViewTestCases.APIViewTestCase): ) FrontPort.objects.bulk_create(front_ports) PortMapping.objects.bulk_create([ - PortMapping(front_port=front_ports[0], rear_port=rear_ports[0]), - PortMapping(front_port=front_ports[1], rear_port=rear_ports[1]), - PortMapping(front_port=front_ports[2], rear_port=rear_ports[2]), + PortMapping(device=device, front_port=front_ports[0], rear_port=rear_ports[0]), + PortMapping(device=device, front_port=front_ports[1], rear_port=rear_ports[1]), + PortMapping(device=device, front_port=front_ports[2], rear_port=rear_ports[2]), ]) cls.create_data = [ @@ -2091,7 +2115,7 @@ class FrontPortTest(APIViewTestCases.APIViewTestCase): interface1 = Interface.objects.create(device=device, name='Interface 1') rear_port = RearPort.objects.create(device=device, name='Rear Port 10', type=PortTypeChoices.TYPE_8P8C) front_port = FrontPort.objects.create(device=device, name='Front Port 10', type=PortTypeChoices.TYPE_8P8C) - PortMapping.objects.create(front_port=front_port, rear_port=rear_port) + PortMapping.objects.create(device=device, front_port=front_port, rear_port=rear_port) Cable.objects.create(a_terminations=[interface1], b_terminations=[front_port]) self.add_permissions(f'dcim.view_{self.model._meta.model_name}') diff --git a/netbox/dcim/tests/test_cablepaths.py b/netbox/dcim/tests/test_cablepaths.py index bbedd856e..1bd613e3b 100644 --- a/netbox/dcim/tests/test_cablepaths.py +++ b/netbox/dcim/tests/test_cablepaths.py @@ -284,6 +284,7 @@ class LegacyCablePathTests(CablePathTestCase): rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1') frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1') PortMapping.objects.create( + device=self.device, front_port=frontport1, front_port_position=1, rear_port=rearport1, @@ -347,6 +348,7 @@ class LegacyCablePathTests(CablePathTestCase): rearport1 = RearPort.objects.create(device=self.device, name='Rear Port 1') frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1') PortMapping.objects.create( + device=self.device, front_port=frontport1, front_port_position=1, rear_port=rearport1, @@ -417,16 +419,32 @@ class LegacyCablePathTests(CablePathTestCase): frontport2_2 = FrontPort.objects.create(device=self.device, name='Front Port 2:2') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1_1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1_1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport1_2, front_port_position=1, rear_port=rearport1, rear_port_position=2, + device=self.device, + front_port=frontport1_2, + front_port_position=1, + rear_port=rearport1, + rear_port_position=2, ), PortMapping( - front_port=frontport2_1, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2_1, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), PortMapping( - front_port=frontport2_2, front_port_position=1, rear_port=rearport2, rear_port_position=2, + device=self.device, + front_port=frontport2_2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=2, ), ]) @@ -541,16 +559,32 @@ class LegacyCablePathTests(CablePathTestCase): frontport2_2 = FrontPort.objects.create(device=self.device, name='Front Port 2:2') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1_1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1_1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport1_2, front_port_position=1, rear_port=rearport1, rear_port_position=2, + device=self.device, + front_port=frontport1_2, + front_port_position=1, + rear_port=rearport1, + rear_port_position=2, ), PortMapping( - front_port=frontport2_1, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2_1, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), PortMapping( - front_port=frontport2_2, front_port_position=1, rear_port=rearport2, rear_port_position=2, + device=self.device, + front_port=frontport2_2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=2, ), ]) @@ -711,22 +745,46 @@ class LegacyCablePathTests(CablePathTestCase): frontport4_2 = FrontPort.objects.create(device=self.device, name='Front Port 4:2') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1_1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1_1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport1_2, front_port_position=1, rear_port=rearport1, rear_port_position=2, + device=self.device, + front_port=frontport1_2, + front_port_position=1, + rear_port=rearport1, + rear_port_position=2, ), PortMapping( - front_port=frontport2, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), PortMapping( - front_port=frontport3, front_port_position=1, rear_port=rearport3, rear_port_position=1, + device=self.device, + front_port=frontport3, + front_port_position=1, + rear_port=rearport3, + rear_port_position=1, ), PortMapping( - front_port=frontport4_1, front_port_position=1, rear_port=rearport4, rear_port_position=1, + device=self.device, + front_port=frontport4_1, + front_port_position=1, + rear_port=rearport4, + rear_port_position=1, ), PortMapping( - front_port=frontport4_2, front_port_position=1, rear_port=rearport4, rear_port_position=2, + device=self.device, + front_port=frontport4_2, + front_port_position=1, + rear_port=rearport4, + rear_port_position=2, ), ]) @@ -839,28 +897,60 @@ class LegacyCablePathTests(CablePathTestCase): frontport4_2 = FrontPort.objects.create(device=self.device, name='Front Port 4:2') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1_1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1_1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport1_2, front_port_position=1, rear_port=rearport1, rear_port_position=2, + device=self.device, + front_port=frontport1_2, + front_port_position=1, + rear_port=rearport1, + rear_port_position=2, ), PortMapping( - front_port=frontport2_1, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2_1, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), PortMapping( - front_port=frontport2_2, front_port_position=1, rear_port=rearport2, rear_port_position=2, + device=self.device, + front_port=frontport2_2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=2, ), PortMapping( - front_port=frontport3_1, front_port_position=1, rear_port=rearport3, rear_port_position=1, + device=self.device, + front_port=frontport3_1, + front_port_position=1, + rear_port=rearport3, + rear_port_position=1, ), PortMapping( - front_port=frontport3_2, front_port_position=1, rear_port=rearport3, rear_port_position=2, + device=self.device, + front_port=frontport3_2, + front_port_position=1, + rear_port=rearport3, + rear_port_position=2, ), PortMapping( - front_port=frontport4_1, front_port_position=1, rear_port=rearport4, rear_port_position=1, + device=self.device, + front_port=frontport4_1, + front_port_position=1, + rear_port=rearport4, + rear_port_position=1, ), PortMapping( - front_port=frontport4_2, front_port_position=1, rear_port=rearport4, rear_port_position=2, + device=self.device, + front_port=frontport4_2, + front_port_position=1, + rear_port=rearport4, + rear_port_position=2, ), ]) @@ -975,19 +1065,39 @@ class LegacyCablePathTests(CablePathTestCase): frontport3_2 = FrontPort.objects.create(device=self.device, name='Front Port 3:2') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1_1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1_1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport1_2, front_port_position=1, rear_port=rearport1, rear_port_position=2, + device=self.device, + front_port=frontport1_2, + front_port_position=1, + rear_port=rearport1, + rear_port_position=2, ), PortMapping( - front_port=frontport2, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), PortMapping( - front_port=frontport3_1, front_port_position=1, rear_port=rearport3, rear_port_position=1, + device=self.device, + front_port=frontport3_1, + front_port_position=1, + rear_port=rearport3, + rear_port_position=1, ), PortMapping( - front_port=frontport3_2, front_port_position=1, rear_port=rearport3, rear_port_position=2, + device=self.device, + front_port=frontport3_2, + front_port_position=1, + rear_port=rearport3, + rear_port_position=2, ), ]) @@ -1082,10 +1192,18 @@ class LegacyCablePathTests(CablePathTestCase): frontport1_2 = FrontPort.objects.create(device=self.device, name='Front Port 1:2') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1_1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1_1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport1_2, front_port_position=1, rear_port=rearport1, rear_port_position=2, + device=self.device, + front_port=frontport1_2, + front_port_position=1, + rear_port=rearport1, + rear_port_position=2, ), ]) @@ -1469,16 +1587,32 @@ class LegacyCablePathTests(CablePathTestCase): frontport2_2 = FrontPort.objects.create(device=self.device, name='Front Port 2:2') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1_1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1_1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport1_2, front_port_position=1, rear_port=rearport1, rear_port_position=2, + device=self.device, + front_port=frontport1_2, + front_port_position=1, + rear_port=rearport1, + rear_port_position=2, ), PortMapping( - front_port=frontport2_1, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2_1, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), PortMapping( - front_port=frontport2_2, front_port_position=1, rear_port=rearport2, rear_port_position=2, + device=self.device, + front_port=frontport2_2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=2, ), ]) circuittermination1 = CircuitTermination.objects.create( @@ -1667,16 +1801,32 @@ class LegacyCablePathTests(CablePathTestCase): frontport4 = FrontPort.objects.create(device=self.device, name='Front Port 4') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport2, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), PortMapping( - front_port=frontport3, front_port_position=1, rear_port=rearport3, rear_port_position=1, + device=self.device, + front_port=frontport3, + front_port_position=1, + rear_port=rearport3, + rear_port_position=1, ), PortMapping( - front_port=frontport4, front_port_position=1, rear_port=rearport4, rear_port_position=1, + device=self.device, + front_port=frontport4, + front_port_position=1, + rear_port=rearport4, + rear_port_position=1, ), ]) @@ -1760,28 +1910,60 @@ class LegacyCablePathTests(CablePathTestCase): frontport2_4 = FrontPort.objects.create(device=self.device, name='Front Port 2:4') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1_1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1_1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport1_2, front_port_position=1, rear_port=rearport1, rear_port_position=2, + device=self.device, + front_port=frontport1_2, + front_port_position=1, + rear_port=rearport1, + rear_port_position=2, ), PortMapping( - front_port=frontport1_3, front_port_position=1, rear_port=rearport1, rear_port_position=3, + device=self.device, + front_port=frontport1_3, + front_port_position=1, + rear_port=rearport1, + rear_port_position=3, ), PortMapping( - front_port=frontport1_4, front_port_position=1, rear_port=rearport1, rear_port_position=4, + device=self.device, + front_port=frontport1_4, + front_port_position=1, + rear_port=rearport1, + rear_port_position=4, ), PortMapping( - front_port=frontport2_1, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2_1, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), PortMapping( - front_port=frontport2_2, front_port_position=1, rear_port=rearport2, rear_port_position=2, + device=self.device, + front_port=frontport2_2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=2, ), PortMapping( - front_port=frontport2_3, front_port_position=1, rear_port=rearport2, rear_port_position=3, + device=self.device, + front_port=frontport2_3, + front_port_position=1, + rear_port=rearport2, + rear_port_position=3, ), PortMapping( - front_port=frontport2_4, front_port_position=1, rear_port=rearport2, rear_port_position=4, + device=self.device, + front_port=frontport2_4, + front_port_position=1, + rear_port=rearport2, + rear_port_position=4, ), ]) @@ -1940,16 +2122,32 @@ class LegacyCablePathTests(CablePathTestCase): frontport4 = FrontPort.objects.create(device=self.device, name='Front Port 4') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport2, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), PortMapping( - front_port=frontport3, front_port_position=1, rear_port=rearport3, rear_port_position=1, + device=self.device, + front_port=frontport3, + front_port_position=1, + rear_port=rearport3, + rear_port_position=1, ), PortMapping( - front_port=frontport4, front_port_position=1, rear_port=rearport4, rear_port_position=1, + device=self.device, + front_port=frontport4, + front_port_position=1, + rear_port=rearport4, + rear_port_position=1, ), ]) @@ -2025,16 +2223,32 @@ class LegacyCablePathTests(CablePathTestCase): frontport4 = FrontPort.objects.create(device=self.device, name='Front Port 4') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport2, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), PortMapping( - front_port=frontport3, front_port_position=1, rear_port=rearport3, rear_port_position=1, + device=self.device, + front_port=frontport3, + front_port_position=1, + rear_port=rearport3, + rear_port_position=1, ), PortMapping( - front_port=frontport4, front_port_position=1, rear_port=rearport4, rear_port_position=1, + device=self.device, + front_port=frontport4, + front_port_position=1, + rear_port=rearport4, + rear_port_position=1, ), ]) @@ -2131,22 +2345,46 @@ class LegacyCablePathTests(CablePathTestCase): frontport6 = FrontPort.objects.create(device=self.device, name='Front Port 6') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport2, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), PortMapping( - front_port=frontport3, front_port_position=1, rear_port=rearport3, rear_port_position=1, + device=self.device, + front_port=frontport3, + front_port_position=1, + rear_port=rearport3, + rear_port_position=1, ), PortMapping( - front_port=frontport4, front_port_position=1, rear_port=rearport4, rear_port_position=1, + device=self.device, + front_port=frontport4, + front_port_position=1, + rear_port=rearport4, + rear_port_position=1, ), PortMapping( - front_port=frontport5, front_port_position=1, rear_port=rearport5, rear_port_position=1, + device=self.device, + front_port=frontport5, + front_port_position=1, + rear_port=rearport5, + rear_port_position=1, ), PortMapping( - front_port=frontport6, front_port_position=1, rear_port=rearport6, rear_port_position=1, + device=self.device, + front_port=frontport6, + front_port_position=1, + rear_port=rearport6, + rear_port_position=1, ), ]) @@ -2253,10 +2491,18 @@ class LegacyCablePathTests(CablePathTestCase): frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport2, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), ]) @@ -2376,10 +2622,18 @@ class LegacyCablePathTests(CablePathTestCase): frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport2, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), ]) @@ -2426,10 +2680,18 @@ class LegacyCablePathTests(CablePathTestCase): frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport2, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), ]) @@ -2481,7 +2743,11 @@ class LegacyCablePathTests(CablePathTestCase): frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), ]) @@ -2595,16 +2861,32 @@ class LegacyCablePathTests(CablePathTestCase): frontport4 = FrontPort.objects.create(device=self.device, name='Front Port 4') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport2, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), PortMapping( - front_port=frontport3, front_port_position=1, rear_port=rearport3, rear_port_position=1, + device=self.device, + front_port=frontport3, + front_port_position=1, + rear_port=rearport3, + rear_port_position=1, ), PortMapping( - front_port=frontport4, front_port_position=1, rear_port=rearport4, rear_port_position=1, + device=self.device, + front_port=frontport4, + front_port_position=1, + rear_port=rearport4, + rear_port_position=1, ), ]) diff --git a/netbox/dcim/tests/test_cablepaths2.py b/netbox/dcim/tests/test_cablepaths2.py index 3a12d755e..66ab58257 100644 --- a/netbox/dcim/tests/test_cablepaths2.py +++ b/netbox/dcim/tests/test_cablepaths2.py @@ -365,7 +365,11 @@ class CablePathTests(CablePathTestCase): frontport1 = FrontPort.objects.create(device=self.device, name='Front Port 1') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), ]) @@ -443,16 +447,32 @@ class CablePathTests(CablePathTestCase): frontport2_2 = FrontPort.objects.create(device=self.device, name='Front Port 2:2') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1_1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1_1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport1_2, front_port_position=1, rear_port=rearport1, rear_port_position=2, + device=self.device, + front_port=frontport1_2, + front_port_position=1, + rear_port=rearport1, + rear_port_position=2, ), PortMapping( - front_port=frontport2_1, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2_1, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), PortMapping( - front_port=frontport2_2, front_port_position=1, rear_port=rearport2, rear_port_position=2, + device=self.device, + front_port=frontport2_2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=2, ), ]) @@ -671,16 +691,32 @@ class CablePathTests(CablePathTestCase): ] PortMapping.objects.bulk_create([ PortMapping( - front_port=front_ports[0], front_port_position=1, rear_port=rear_ports[0], rear_port_position=1, + device=self.device, + front_port=front_ports[0], + front_port_position=1, + rear_port=rear_ports[0], + rear_port_position=1, ), PortMapping( - front_port=front_ports[1], front_port_position=1, rear_port=rear_ports[1], rear_port_position=1, + device=self.device, + front_port=front_ports[1], + front_port_position=1, + rear_port=rear_ports[1], + rear_port_position=1, ), PortMapping( - front_port=front_ports[2], front_port_position=1, rear_port=rear_ports[2], rear_port_position=1, + device=self.device, + front_port=front_ports[2], + front_port_position=1, + rear_port=rear_ports[2], + rear_port_position=1, ), PortMapping( - front_port=front_ports[3], front_port_position=1, rear_port=rear_ports[3], rear_port_position=1, + device=self.device, + front_port=front_ports[3], + front_port_position=1, + rear_port=rear_ports[3], + rear_port_position=1, ), ]) @@ -750,10 +786,18 @@ class CablePathTests(CablePathTestCase): frontport2 = FrontPort.objects.create(device=self.device, name='Front Port 2') PortMapping.objects.bulk_create([ PortMapping( - front_port=frontport1, front_port_position=1, rear_port=rearport1, rear_port_position=1, + device=self.device, + front_port=frontport1, + front_port_position=1, + rear_port=rearport1, + rear_port_position=1, ), PortMapping( - front_port=frontport2, front_port_position=1, rear_port=rearport2, rear_port_position=1, + device=self.device, + front_port=frontport2, + front_port_position=1, + rear_port=rearport2, + rear_port_position=1, ), ]) diff --git a/netbox/dcim/tests/test_filtersets.py b/netbox/dcim/tests/test_filtersets.py index 7b83cfbbe..296f6d433 100644 --- a/netbox/dcim/tests/test_filtersets.py +++ b/netbox/dcim/tests/test_filtersets.py @@ -1361,8 +1361,8 @@ class DeviceTypeTestCase(TestCase, ChangeLoggedFilterSetTests): ) FrontPortTemplate.objects.bulk_create(front_ports) PortTemplateMapping.objects.bulk_create([ - PortTemplateMapping(front_port=front_ports[0], rear_port=rear_ports[0]), - PortTemplateMapping(front_port=front_ports[1], rear_port=rear_ports[1]), + PortTemplateMapping(device_type=device_types[0], front_port=front_ports[0], rear_port=rear_ports[0]), + PortTemplateMapping(device_type=device_types[1], front_port=front_ports[1], rear_port=rear_ports[1]), ]) ModuleBayTemplate.objects.bulk_create(( ModuleBayTemplate(device_type=device_types[0], name='Module Bay 1'), @@ -1625,8 +1625,8 @@ class ModuleTypeTestCase(TestCase, ChangeLoggedFilterSetTests): ) FrontPortTemplate.objects.bulk_create(front_ports) PortTemplateMapping.objects.bulk_create([ - PortTemplateMapping(front_port=front_ports[0], rear_port=rear_ports[0]), - PortTemplateMapping(front_port=front_ports[1], rear_port=rear_ports[1]), + PortTemplateMapping(module_type=module_types[0], front_port=front_ports[0], rear_port=rear_ports[0]), + PortTemplateMapping(module_type=module_types[1], front_port=front_ports[1], rear_port=rear_ports[1]), ]) def test_q(self): @@ -2068,9 +2068,9 @@ class FrontPortTemplateTestCase(TestCase, DeviceComponentTemplateFilterSetTests, ) FrontPortTemplate.objects.bulk_create(front_ports) PortTemplateMapping.objects.bulk_create([ - PortTemplateMapping(front_port=front_ports[0], rear_port=rear_ports[0]), - PortTemplateMapping(front_port=front_ports[1], rear_port=rear_ports[1]), - PortTemplateMapping(front_port=front_ports[2], rear_port=rear_ports[2]), + PortTemplateMapping(device_type=device_types[0], front_port=front_ports[0], rear_port=rear_ports[0]), + PortTemplateMapping(device_type=device_types[1], front_port=front_ports[1], rear_port=rear_ports[1]), + PortTemplateMapping(device_type=device_types[2], front_port=front_ports[2], rear_port=rear_ports[2]), ]) def test_name(self): @@ -2747,8 +2747,8 @@ class DeviceTestCase(TestCase, ChangeLoggedFilterSetTests): ) FrontPort.objects.bulk_create(front_ports) PortMapping.objects.bulk_create([ - PortMapping(front_port=front_ports[0], rear_port=rear_ports[0]), - PortMapping(front_port=front_ports[1], rear_port=rear_ports[1]), + PortMapping(device=devices[0], front_port=front_ports[0], rear_port=rear_ports[0]), + PortMapping(device=devices[1], front_port=front_ports[1], rear_port=rear_ports[1]), ]) ModuleBay.objects.create(device=devices[0], name='Module Bay 1') ModuleBay.objects.create(device=devices[1], name='Module Bay 2') @@ -5143,12 +5143,12 @@ class FrontPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil ) FrontPort.objects.bulk_create(front_ports) PortMapping.objects.bulk_create([ - PortMapping(front_port=front_ports[0], rear_port=rear_ports[0]), - PortMapping(front_port=front_ports[1], rear_port=rear_ports[1], rear_port_position=2), - PortMapping(front_port=front_ports[2], rear_port=rear_ports[2], rear_port_position=3), - PortMapping(front_port=front_ports[3], rear_port=rear_ports[3]), - PortMapping(front_port=front_ports[4], rear_port=rear_ports[4]), - PortMapping(front_port=front_ports[5], rear_port=rear_ports[5]), + PortMapping(device=devices[0], front_port=front_ports[0], rear_port=rear_ports[0]), + PortMapping(device=devices[1], front_port=front_ports[1], rear_port=rear_ports[1], rear_port_position=2), + PortMapping(device=devices[2], front_port=front_ports[2], rear_port=rear_ports[2], rear_port_position=3), + PortMapping(device=devices[3], front_port=front_ports[3], rear_port=rear_ports[3]), + PortMapping(device=devices[3], front_port=front_ports[4], rear_port=rear_ports[4]), + PortMapping(device=devices[3], front_port=front_ports[5], rear_port=rear_ports[5]), ]) # Cables @@ -6412,7 +6412,7 @@ class CableTestCase(TestCase, ChangeLoggedFilterSetTests): power_outlet = PowerOutlet.objects.create(device=devices[0], name='Power Outlet 1') rear_port = RearPort.objects.create(device=devices[0], name='Rear Port 1') front_port = FrontPort.objects.create(device=devices[0], name='Front Port 1') - PortMapping.objects.create(front_port=front_port, rear_port=rear_port) + PortMapping.objects.create(device=devices[0], front_port=front_port, rear_port=rear_port) power_panel = PowerPanel.objects.create(name='Power Panel 1', site=sites[0]) power_feed = PowerFeed.objects.create(name='Power Feed 1', power_panel=power_panel) diff --git a/netbox/dcim/tests/test_models.py b/netbox/dcim/tests/test_models.py index 1f332ed21..b3eff0920 100644 --- a/netbox/dcim/tests/test_models.py +++ b/netbox/dcim/tests/test_models.py @@ -452,6 +452,7 @@ class DeviceTestCase(TestCase): frontport.save() PortTemplateMapping.objects.create( + device_type=device_type, front_port=frontport, rear_port=rearport, rear_port_position=2, @@ -848,10 +849,10 @@ class CableTestCase(TestCase): ) FrontPort.objects.bulk_create(front_ports) PortMapping.objects.bulk_create([ - PortMapping(front_port=front_ports[0], rear_port=rear_ports[0]), - PortMapping(front_port=front_ports[1], rear_port=rear_ports[1]), - PortMapping(front_port=front_ports[2], rear_port=rear_ports[2]), - PortMapping(front_port=front_ports[3], rear_port=rear_ports[3]), + PortMapping(device=patch_panel, front_port=front_ports[0], rear_port=rear_ports[0]), + PortMapping(device=patch_panel, front_port=front_ports[1], rear_port=rear_ports[1]), + PortMapping(device=patch_panel, front_port=front_ports[2], rear_port=rear_ports[2]), + PortMapping(device=patch_panel, front_port=front_ports[3], rear_port=rear_ports[3]), ]) provider = Provider.objects.create(name='Provider 1', slug='provider-1') diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 6b179cea8..1bf8ed99c 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -747,9 +747,9 @@ class DeviceTypeTestCase( ) FrontPortTemplate.objects.bulk_create(front_ports) PortTemplateMapping.objects.bulk_create([ - PortTemplateMapping(front_port=front_ports[0], rear_port=rear_ports[0]), - PortTemplateMapping(front_port=front_ports[1], rear_port=rear_ports[1]), - PortTemplateMapping(front_port=front_ports[2], rear_port=rear_ports[2]), + PortTemplateMapping(device_type=devicetype, front_port=front_ports[0], rear_port=rear_ports[0]), + PortTemplateMapping(device_type=devicetype, front_port=front_ports[1], rear_port=rear_ports[1]), + PortTemplateMapping(device_type=devicetype, front_port=front_ports[2], rear_port=rear_ports[2]), ]) url = reverse('dcim:devicetype_frontports', kwargs={'pk': devicetype.pk}) @@ -1319,9 +1319,9 @@ class ModuleTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase): ) FrontPortTemplate.objects.bulk_create(front_ports) PortTemplateMapping.objects.bulk_create([ - PortTemplateMapping(front_port=front_ports[0], rear_port=rear_ports[0]), - PortTemplateMapping(front_port=front_ports[1], rear_port=rear_ports[1]), - PortTemplateMapping(front_port=front_ports[2], rear_port=rear_ports[2]), + PortTemplateMapping(module_type=moduletype, front_port=front_ports[0], rear_port=rear_ports[0]), + PortTemplateMapping(module_type=moduletype, front_port=front_ports[1], rear_port=rear_ports[1]), + PortTemplateMapping(module_type=moduletype, front_port=front_ports[2], rear_port=rear_ports[2]), ]) url = reverse('dcim:moduletype_frontports', kwargs={'pk': moduletype.pk}) @@ -1777,9 +1777,9 @@ class FrontPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCas ) FrontPortTemplate.objects.bulk_create(front_ports) PortTemplateMapping.objects.bulk_create([ - PortTemplateMapping(front_port=front_ports[0], rear_port=rear_ports[0]), - PortTemplateMapping(front_port=front_ports[1], rear_port=rear_ports[1]), - PortTemplateMapping(front_port=front_ports[2], rear_port=rear_ports[2]), + PortTemplateMapping(device_type=devicetype, front_port=front_ports[0], rear_port=rear_ports[0]), + PortTemplateMapping(device_type=devicetype, front_port=front_ports[1], rear_port=rear_ports[1]), + PortTemplateMapping(device_type=devicetype, front_port=front_ports[2], rear_port=rear_ports[2]), ]) cls.form_data = { @@ -2271,9 +2271,9 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase): ) FrontPort.objects.bulk_create(front_ports) PortMapping.objects.bulk_create([ - PortMapping(front_port=front_ports[0], rear_port=rear_ports[0]), - PortMapping(front_port=front_ports[1], rear_port=rear_ports[1]), - PortMapping(front_port=front_ports[2], rear_port=rear_ports[2]), + PortMapping(device=device, front_port=front_ports[0], rear_port=rear_ports[0]), + PortMapping(device=device, front_port=front_ports[1], rear_port=rear_ports[1]), + PortMapping(device=device, front_port=front_ports[2], rear_port=rear_ports[2]), ]) url = reverse('dcim:device_frontports', kwargs={'pk': device.pk}) @@ -3076,9 +3076,9 @@ class FrontPortTestCase(ViewTestCases.DeviceComponentViewTestCase): ) FrontPort.objects.bulk_create(front_ports) PortMapping.objects.bulk_create([ - PortMapping(front_port=front_ports[0], rear_port=rear_ports[0]), - PortMapping(front_port=front_ports[1], rear_port=rear_ports[1]), - PortMapping(front_port=front_ports[2], rear_port=rear_ports[2]), + PortMapping(device=device, front_port=front_ports[0], rear_port=rear_ports[0]), + PortMapping(device=device, front_port=front_ports[1], rear_port=rear_ports[1]), + PortMapping(device=device, front_port=front_ports[2], rear_port=rear_ports[2]), ]) tags = create_tags('Alpha', 'Bravo', 'Charlie') diff --git a/netbox/dcim/utils.py b/netbox/dcim/utils.py index f5b94829e..ce4a8c8d5 100644 --- a/netbox/dcim/utils.py +++ b/netbox/dcim/utils.py @@ -89,11 +89,9 @@ def create_port_mappings(device, device_type, module=None): """ Replicate all front/rear port mappings from a DeviceType to the given device. """ - from dcim.models import FrontPort, PortMapping, PortTemplateMapping, RearPort + from dcim.models import FrontPort, PortMapping, RearPort - templates = PortTemplateMapping.objects.filter( - front_port__device_type=device_type - ).prefetch_related('front_port', 'rear_port') + templates = device_type.port_mappings.prefetch_related('front_port', 'rear_port') # Cache front & rear ports for efficient lookups by name front_ports = { @@ -110,6 +108,7 @@ def create_port_mappings(device, device_type, module=None): rear_port = rear_ports.get(template.rear_port.resolve_name(module=module)) mappings.append( PortMapping( + device_id=front_port.device_id, front_port=front_port, front_port_position=template.front_port_position, rear_port=rear_port,