Преглед на файлове

Closes #19499 - Add WirelessLink Bulk Import Support by Device and Interface Names (#19679)

Martin Hauser преди 8 месеца
родител
ревизия
e6c1cebd34
променени са 3 файла, в които са добавени 72 реда и са изтрити 15 реда
  1. 66 9
      netbox/wireless/forms/bulk_import.py
  2. 2 2
      netbox/wireless/models.py
  3. 4 4
      netbox/wireless/tests/test_views.py

+ 66 - 9
netbox/wireless/forms/bulk_import.py

@@ -2,7 +2,7 @@ from django.utils.translation import gettext_lazy as _
 
 from dcim.choices import LinkStatusChoices
 from dcim.forms.mixins import ScopedImportForm
-from dcim.models import Interface
+from dcim.models import Device, Interface, Site
 from ipam.models import VLAN
 from netbox.choices import *
 from netbox.forms import NetBoxModelImportForm
@@ -85,18 +85,53 @@ class WirelessLANImportForm(ScopedImportForm, NetBoxModelImportForm):
 
 
 class WirelessLinkImportForm(NetBoxModelImportForm):
-    status = CSVChoiceField(
-        label=_('Status'),
-        choices=LinkStatusChoices,
-        help_text=_('Connection status')
+    # Termination A
+    site_a = CSVModelChoiceField(
+        label=_('Site A'),
+        queryset=Site.objects.all(),
+        required=False,
+        to_field_name='name',
+        help_text=_('Site of parent device A (if any)'),
+    )
+    device_a = CSVModelChoiceField(
+        label=_('Device A'),
+        queryset=Device.objects.all(),
+        to_field_name='name',
+        help_text=_('Parent device of assigned interface A'),
     )
     interface_a = CSVModelChoiceField(
         label=_('Interface A'),
-        queryset=Interface.objects.all()
+        queryset=Interface.objects.all(),
+        to_field_name='name',
+        help_text=_('Assigned interface A'),
+    )
+
+    # Termination B
+    site_b = CSVModelChoiceField(
+        label=_('Site B'),
+        queryset=Site.objects.all(),
+        required=False,
+        to_field_name='name',
+        help_text=_('Site of parent device B (if any)'),
+    )
+    device_b = CSVModelChoiceField(
+        label=_('Device B'),
+        queryset=Device.objects.all(),
+        to_field_name='name',
+        help_text=_('Parent device of assigned interface B'),
     )
     interface_b = CSVModelChoiceField(
         label=_('Interface B'),
-        queryset=Interface.objects.all()
+        queryset=Interface.objects.all(),
+        to_field_name='name',
+        help_text=_('Assigned interface B'),
+    )
+
+    # WirelessLink attributes
+    status = CSVChoiceField(
+        label=_('Status'),
+        choices=LinkStatusChoices,
+        help_text=_('Connection status'),
     )
     tenant = CSVModelChoiceField(
         label=_('Tenant'),
@@ -127,6 +162,28 @@ class WirelessLinkImportForm(NetBoxModelImportForm):
     class Meta:
         model = WirelessLink
         fields = (
-            'interface_a', 'interface_b', 'ssid', 'tenant', 'auth_type', 'auth_cipher', 'auth_psk',
-            'distance', 'distance_unit', 'description', 'comments', 'tags',
+            'site_a', 'device_a', 'interface_a', 'site_b', 'device_b', 'interface_b', 'status', 'ssid', 'tenant',
+            'auth_type', 'auth_cipher', 'auth_psk', 'distance', 'distance_unit', 'description', 'comments', 'tags',
         )
+
+    def __init__(self, data=None, *args, **kwargs):
+        super().__init__(data, *args, **kwargs)
+
+        if data:
+            # Limit choices for interface_a to the assigned device_a
+            interface_a_params = {f'device__{self.fields["device_a"].to_field_name}': data.get('device_a')}
+            # Limit choices for device_a to the assigned site_a
+            if site_a := data.get('site_a'):
+                device_a_params = {f'site__{self.fields["site_a"].to_field_name}': site_a}
+                self.fields['device_a'].queryset = self.fields['device_a'].queryset.filter(**device_a_params)
+                interface_a_params.update({f'device__site__{self.fields["site_a"].to_field_name}': site_a})
+            self.fields['interface_a'].queryset = self.fields['interface_a'].queryset.filter(**interface_a_params)
+
+            # Limit choices for interface_b to the assigned device_b
+            interface_b_params = {f'device__{self.fields["device_b"].to_field_name}': data.get('device_b')}
+            # Limit choices for device_b to the assigned site_b
+            if site_b := data.get('site_b'):
+                device_b_params = {f'site__{self.fields["site_b"].to_field_name}': site_b}
+                self.fields['device_b'].queryset = self.fields['device_b'].queryset.filter(**device_b_params)
+                interface_b_params.update({f'device__site__{self.fields["site_b"].to_field_name}': site_b})
+            self.fields['interface_b'].queryset = self.fields['interface_b'].queryset.filter(**interface_b_params)

+ 2 - 2
netbox/wireless/models.py

@@ -198,13 +198,13 @@ class WirelessLink(WirelessAuthenticationBase, DistanceMixin, PrimaryModel):
         super().clean()
 
         # Validate interface types
-        if self.interface_a.type not in WIRELESS_IFACE_TYPES:
+        if hasattr(self, "interface_a") and self.interface_a.type not in WIRELESS_IFACE_TYPES:
             raise ValidationError({
                 'interface_a': _(
                     "{type} is not a wireless interface."
                 ).format(type=self.interface_a.get_type_display())
             })
-        if self.interface_b.type not in WIRELESS_IFACE_TYPES:
+        if hasattr(self, "interface_b") and self.interface_b.type not in WIRELESS_IFACE_TYPES:
             raise ValidationError({
                 'interface_b': _(
                     "{type} is not a wireless interface."

+ 4 - 4
netbox/wireless/tests/test_views.py

@@ -198,10 +198,10 @@ class WirelessLinkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         }
 
         cls.csv_data = (
-            "interface_a,interface_b,status,tenant",
-            f"{interfaces[6].pk},{interfaces[7].pk},connected,{tenants[0].name}",
-            f"{interfaces[8].pk},{interfaces[9].pk},connected,{tenants[1].name}",
-            f"{interfaces[10].pk},{interfaces[11].pk},connected,{tenants[2].name}",
+            "device_a,interface_a,device_b,interface_b,status,tenant",
+            f"{interfaces[6].device.name},{interfaces[6].name},{interfaces[7].device.name},{interfaces[7].name},connected,{tenants[0].name}",
+            f"{interfaces[8].device.name},{interfaces[8].name},{interfaces[9].device.name},{interfaces[9].name},connected,{tenants[1].name}",
+            f"{interfaces[10].device.name},{interfaces[10].name},{interfaces[11].device.name},{interfaces[11].name},connected,{tenants[2].name}",
         )
 
         cls.csv_update_data = (