Просмотр исходного кода

13972 allow filtering of cables if have terminations (#13949)

* 10769 allow filtering of cables if have terminations

* 10769 change to termianted

* 10769 add test case

* 10769 review cleanup
Arthur Hanson 2 лет назад
Родитель
Сommit
18a813aa39
3 измененных файлов с 35 добавлено и 1 удалено
  1. 17 0
      netbox/dcim/filtersets.py
  2. 8 1
      netbox/dcim/forms/filtersets.py
  3. 10 0
      netbox/dcim/tests/test_filtersets.py

+ 17 - 0
netbox/dcim/filtersets.py

@@ -1745,6 +1745,10 @@ class CableFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
         method='filter_by_cable_end_b',
         field_name='terminations__termination_id'
     )
+    unterminated = django_filters.BooleanFilter(
+        method='_unterminated',
+        label=_('Unterminated'),
+    )
     type = django_filters.MultipleChoiceFilter(
         choices=CableTypeChoices
     )
@@ -1812,6 +1816,19 @@ class CableFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
         # Filter by termination id and cable_end type
         return self.filter_by_cable_end(queryset, name, value, CableEndChoices.SIDE_B)
 
+    def _unterminated(self, queryset, name, value):
+        if value:
+            terminated_ids = (
+                queryset.filter(terminations__cable_end=CableEndChoices.SIDE_A)
+                .filter(terminations__cable_end=CableEndChoices.SIDE_B)
+                .values("id")
+            )
+            return queryset.exclude(id__in=terminated_ids)
+        else:
+            return queryset.filter(terminations__cable_end=CableEndChoices.SIDE_A).filter(
+                terminations__cable_end=CableEndChoices.SIDE_B
+            )
+
 
 class CableTerminationFilterSet(BaseFilterSet):
     termination_type = ContentTypeFilter()

+ 8 - 1
netbox/dcim/forms/filtersets.py

@@ -910,7 +910,7 @@ class CableFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     fieldsets = (
         (None, ('q', 'filter_id', 'tag')),
         (_('Location'), ('site_id', 'location_id', 'rack_id', 'device_id')),
-        (_('Attributes'), ('type', 'status', 'color', 'length', 'length_unit')),
+        (_('Attributes'), ('type', 'status', 'color', 'length', 'length_unit', 'unterminated')),
         (_('Tenant'), ('tenant_group_id', 'tenant_id')),
     )
     region_id = DynamicModelMultipleChoiceField(
@@ -979,6 +979,13 @@ class CableFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
         choices=add_blank_choice(CableLengthUnitChoices),
         required=False
     )
+    unterminated = forms.NullBooleanField(
+        label=_('Unterminated'),
+        required=False,
+        widget=forms.Select(
+            choices=BOOLEAN_WITH_BLANK_CHOICES
+        )
+    )
     tag = TagFilterField(model)
 
 

+ 10 - 0
netbox/dcim/tests/test_filtersets.py

@@ -4275,6 +4275,7 @@ class CableTestCase(TestCase, ChangeLoggedFilterSetTests):
             Interface(device=devices[4], name='Interface 10', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
             Interface(device=devices[5], name='Interface 11', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
             Interface(device=devices[5], name='Interface 12', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+            Interface(device=devices[5], name='Interface 13', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
         )
         Interface.objects.bulk_create(interfaces)
 
@@ -4290,6 +4291,9 @@ class CableTestCase(TestCase, ChangeLoggedFilterSetTests):
         Cable(a_terminations=[interfaces[11]], b_terminations=[interfaces[0]], label='Cable 6', type=CableTypeChoices.TYPE_CAT6, tenant=tenants[2], status=LinkStatusChoices.STATUS_PLANNED, color='e91e63', length=20, length_unit=CableLengthUnitChoices.UNIT_METER).save()
         Cable(a_terminations=[console_port], b_terminations=[console_server_port], label='Cable 7').save()
 
+        # Cable for unterminated test
+        Cable(a_terminations=[interfaces[12]], label='Cable 8', type=CableTypeChoices.TYPE_CAT6, status=LinkStatusChoices.STATUS_DECOMMISSIONING).save()
+
     def test_label(self):
         params = {'label': ['Cable 1', 'Cable 2']}
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@@ -4368,6 +4372,12 @@ class CableTestCase(TestCase, ChangeLoggedFilterSetTests):
         }
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
 
+    def test_unterminated(self):
+        params = {'unterminated': True}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
+        params = {'unterminated': False}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 7)
+
 
 class PowerPanelTestCase(TestCase, ChangeLoggedFilterSetTests):
     queryset = PowerPanel.objects.all()