2
0
Эх сурвалжийг харах

Fixes #21124: Fix rear port selection when creating front ports on a module type

Jeremy Stretch 1 сар өмнө
parent
commit
fff99fd3ff

+ 19 - 3
netbox/dcim/forms/mixins.py

@@ -140,9 +140,6 @@ class FrontPortFormMixin(forms.Form):
         widget=forms.SelectMultiple(attrs={'size': 8})
         widget=forms.SelectMultiple(attrs={'size': 8})
     )
     )
 
 
-    port_mapping_model = PortMapping
-    parent_field = 'device'
-
     def clean(self):
     def clean(self):
         super().clean()
         super().clean()
 
 
@@ -203,3 +200,22 @@ class FrontPortFormMixin(forms.Form):
                 using=connection,
                 using=connection,
                 update_fields=None
                 update_fields=None
             )
             )
+
+    def _get_rear_port_choices(self, parent_filter, front_port):
+        """
+        Return a list of choices representing each available rear port & position pair on the parent object (identified
+        by a Q filter), excluding those assigned to the specified instance.
+        """
+        occupied_rear_port_positions = [
+            f'{mapping.rear_port_id}:{mapping.rear_port_position}'
+            for mapping in self.port_mapping_model.objects.filter(parent_filter).exclude(front_port=front_port.pk)
+        ]
+
+        choices = []
+        for rear_port in self.rear_port_model.objects.filter(parent_filter):
+            for i in range(1, rear_port.positions + 1):
+                pair_id = f'{rear_port.pk}:{i}'
+                if pair_id not in occupied_rear_port_positions:
+                    pair_label = f'{rear_port.name}:{i}'
+                    choices.append((pair_id, pair_label))
+        return choices

+ 12 - 52
netbox/dcim/forms/model_forms.py

@@ -1124,9 +1124,8 @@ class FrontPortTemplateForm(FrontPortFormMixin, ModularComponentTemplateForm):
         ),
         ),
     )
     )
 
 
-    # Override FrontPortFormMixin attrs
     port_mapping_model = PortTemplateMapping
     port_mapping_model = PortTemplateMapping
-    parent_field = 'device_type'
+    rear_port_model = RearPortTemplate
 
 
     class Meta:
     class Meta:
         model = FrontPortTemplate
         model = FrontPortTemplate
@@ -1137,13 +1136,14 @@ class FrontPortTemplateForm(FrontPortFormMixin, ModularComponentTemplateForm):
     def __init__(self, *args, **kwargs):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         super().__init__(*args, **kwargs)
 
 
+        # Populate rear port choices based on parent DeviceType or ModuleType
         if device_type_id := self.data.get('device_type') or self.initial.get('device_type'):
         if device_type_id := self.data.get('device_type') or self.initial.get('device_type'):
-            device_type = DeviceType.objects.get(pk=device_type_id)
+            parent_filter = Q(device_type=device_type_id)
+        elif module_type_id := self.data.get('module_type') or self.initial.get('module_type'):
+            parent_filter = Q(module_type=module_type_id)
         else:
         else:
             return
             return
-
-        # Populate rear port choices
-        self.fields['rear_ports'].choices = self._get_rear_port_choices(device_type, self.instance)
+        self.fields['rear_ports'].choices = self._get_rear_port_choices(parent_filter, self.instance)
 
 
         # Set initial rear port mappings
         # Set initial rear port mappings
         if self.instance.pk:
         if self.instance.pk:
@@ -1152,27 +1152,6 @@ class FrontPortTemplateForm(FrontPortFormMixin, ModularComponentTemplateForm):
                 for mapping in PortTemplateMapping.objects.filter(front_port_id=self.instance.pk)
                 for mapping in PortTemplateMapping.objects.filter(front_port_id=self.instance.pk)
             ]
             ]
 
 
-    def _get_rear_port_choices(self, device_type, front_port):
-        """
-        Return a list of choices representing each available rear port & position pair on the device type, excluding
-        those assigned to the specified instance.
-        """
-        occupied_rear_port_positions = [
-            f'{mapping.rear_port_id}:{mapping.rear_port_position}'
-            for mapping in device_type.port_mappings.exclude(front_port=front_port.pk)
-        ]
-
-        choices = []
-        for rear_port in RearPortTemplate.objects.filter(device_type=device_type):
-            for i in range(1, rear_port.positions + 1):
-                pair_id = f'{rear_port.pk}:{i}'
-                if pair_id not in occupied_rear_port_positions:
-                    pair_label = f'{rear_port.name}:{i}'
-                    choices.append(
-                        (pair_id, pair_label)
-                    )
-        return choices
-
 
 
 class RearPortTemplateForm(ModularComponentTemplateForm):
 class RearPortTemplateForm(ModularComponentTemplateForm):
     fieldsets = (
     fieldsets = (
@@ -1619,6 +1598,9 @@ class FrontPortForm(FrontPortFormMixin, ModularDeviceComponentForm):
         ),
         ),
     )
     )
 
 
+    port_mapping_model = PortMapping
+    rear_port_model = RearPort
+
     class Meta:
     class Meta:
         model = FrontPort
         model = FrontPort
         fields = [
         fields = [
@@ -1629,13 +1611,12 @@ class FrontPortForm(FrontPortFormMixin, ModularDeviceComponentForm):
     def __init__(self, *args, **kwargs):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         super().__init__(*args, **kwargs)
 
 
+        # Populate rear port choices
         if device_id := self.data.get('device') or self.initial.get('device'):
         if device_id := self.data.get('device') or self.initial.get('device'):
-            device = Device.objects.get(pk=device_id)
+            parent_filter = Q(device=device_id)
         else:
         else:
             return
             return
-
-        # Populate rear port choices
-        self.fields['rear_ports'].choices = self._get_rear_port_choices(device, self.instance)
+        self.fields['rear_ports'].choices = self._get_rear_port_choices(parent_filter, self.instance)
 
 
         # Set initial rear port mappings
         # Set initial rear port mappings
         if self.instance.pk:
         if self.instance.pk:
@@ -1644,27 +1625,6 @@ class FrontPortForm(FrontPortFormMixin, ModularDeviceComponentForm):
                 for mapping in PortMapping.objects.filter(front_port_id=self.instance.pk)
                 for mapping in PortMapping.objects.filter(front_port_id=self.instance.pk)
             ]
             ]
 
 
-    def _get_rear_port_choices(self, device, front_port):
-        """
-        Return a list of choices representing each available rear port & position pair on the device, excluding those
-        assigned to the specified instance.
-        """
-        occupied_rear_port_positions = [
-            f'{mapping.rear_port_id}:{mapping.rear_port_position}'
-            for mapping in device.port_mappings.exclude(front_port=front_port.pk)
-        ]
-
-        choices = []
-        for rear_port in RearPort.objects.filter(device=device):
-            for i in range(1, rear_port.positions + 1):
-                pair_id = f'{rear_port.pk}:{i}'
-                if pair_id not in occupied_rear_port_positions:
-                    pair_label = f'{rear_port.name}:{i}'
-                    choices.append(
-                        (pair_id, pair_label)
-                    )
-        return choices
-
 
 
 class RearPortForm(ModularDeviceComponentForm):
 class RearPortForm(ModularDeviceComponentForm):
     fieldsets = (
     fieldsets = (