From 9ef9443969439dc9e54f0d35a8ddfac845557d39 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 16 May 2022 16:16:51 -0400 Subject: [PATCH] Add REST API endpoint for CableTermination --- netbox/circuits/filtersets.py | 4 ++-- netbox/dcim/api/serializers.py | 20 ++++++++++++++++++++ netbox/dcim/api/urls.py | 1 + netbox/dcim/api/views.py | 8 +++++++- netbox/dcim/filtersets.py | 26 +++++++++++++++++--------- netbox/dcim/models/cables.py | 3 +++ 6 files changed, 50 insertions(+), 12 deletions(-) diff --git a/netbox/circuits/filtersets.py b/netbox/circuits/filtersets.py index b7fa100a8..2087d90d2 100644 --- a/netbox/circuits/filtersets.py +++ b/netbox/circuits/filtersets.py @@ -1,7 +1,7 @@ import django_filters from django.db.models import Q -from dcim.filtersets import CableTerminationFilterSet +from dcim.filtersets import CabledObjectFilterSet from dcim.models import Region, Site, SiteGroup from ipam.models import ASN from netbox.filtersets import ChangeLoggedModelFilterSet, NetBoxModelFilterSet, OrganizationalModelFilterSet @@ -198,7 +198,7 @@ class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte ).distinct() -class CircuitTerminationFilterSet(ChangeLoggedModelFilterSet, CableTerminationFilterSet): +class CircuitTerminationFilterSet(ChangeLoggedModelFilterSet, CabledObjectFilterSet): q = django_filters.CharFilter( method='search', label='Search', diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index 98ec8979d..53f5d1327 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -1061,6 +1061,26 @@ class TracedCableSerializer(serializers.ModelSerializer): ] +class CableTerminationSerializer(NetBoxModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cable-detail') + termination_type = ContentTypeField( + queryset=ContentType.objects.filter(CABLE_TERMINATION_MODELS) + ) + termination = serializers.SerializerMethodField(read_only=True) + + class Meta: + model = CableTermination + fields = [ + 'id', 'url', 'display', 'cable', 'cable_end', 'termination_type', 'termination_id', 'termination' + ] + + @swagger_serializer_method(serializer_or_field=serializers.DictField) + def get_termination(self, obj): + serializer = get_serializer_for_model(obj.termination, prefix='Nested') + context = {'request': self.context['request']} + return serializer(obj.termination, context=context).data + + class CablePathSerializer(serializers.ModelSerializer): origin_type = ContentTypeField(read_only=True) origin = serializers.SerializerMethodField(read_only=True) diff --git a/netbox/dcim/api/urls.py b/netbox/dcim/api/urls.py index f67d241d5..e73678f71 100644 --- a/netbox/dcim/api/urls.py +++ b/netbox/dcim/api/urls.py @@ -56,6 +56,7 @@ router.register('inventory-item-roles', views.InventoryItemRoleViewSet) # Cables router.register('cables', views.CableViewSet) +router.register('cable-terminations', views.CableTerminationViewSet) # Virtual chassis router.register('virtual-chassis', views.VirtualChassisViewSet) diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index 60809b051..363523819 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -646,12 +646,18 @@ class InventoryItemRoleViewSet(NetBoxModelViewSet): # class CableViewSet(NetBoxModelViewSet): - metadata_class = ContentTypeMetadata queryset = Cable.objects.prefetch_related('terminations__termination') serializer_class = serializers.CableSerializer filterset_class = filtersets.CableFilterSet +class CableTerminationViewSet(NetBoxModelViewSet): + metadata_class = ContentTypeMetadata + queryset = CableTermination.objects.prefetch_related('cable', 'termination') + serializer_class = serializers.CableTerminationSerializer + filterset_class = filtersets.CableTerminationFilterSet + + # # Virtual chassis # diff --git a/netbox/dcim/filtersets.py b/netbox/dcim/filtersets.py index 6fefe4ac0..7da042253 100644 --- a/netbox/dcim/filtersets.py +++ b/netbox/dcim/filtersets.py @@ -21,6 +21,7 @@ from .models import * __all__ = ( 'CableFilterSet', + 'CabledObjectFilterSet', 'CableTerminationFilterSet', 'ConsoleConnectionFilterSet', 'ConsolePortFilterSet', @@ -1107,7 +1108,7 @@ class ModularDeviceComponentFilterSet(DeviceComponentFilterSet): ) -class CableTerminationFilterSet(django_filters.FilterSet): +class CabledObjectFilterSet(django_filters.FilterSet): cabled = django_filters.BooleanFilter( field_name='cable', lookup_expr='isnull', @@ -1130,7 +1131,7 @@ class PathEndpointFilterSet(django_filters.FilterSet): class ConsolePortFilterSet( ModularDeviceComponentFilterSet, NetBoxModelFilterSet, - CableTerminationFilterSet, + CabledObjectFilterSet, PathEndpointFilterSet ): type = django_filters.MultipleChoiceFilter( @@ -1146,7 +1147,7 @@ class ConsolePortFilterSet( class ConsoleServerPortFilterSet( ModularDeviceComponentFilterSet, NetBoxModelFilterSet, - CableTerminationFilterSet, + CabledObjectFilterSet, PathEndpointFilterSet ): type = django_filters.MultipleChoiceFilter( @@ -1162,7 +1163,7 @@ class ConsoleServerPortFilterSet( class PowerPortFilterSet( ModularDeviceComponentFilterSet, NetBoxModelFilterSet, - CableTerminationFilterSet, + CabledObjectFilterSet, PathEndpointFilterSet ): type = django_filters.MultipleChoiceFilter( @@ -1178,7 +1179,7 @@ class PowerPortFilterSet( class PowerOutletFilterSet( ModularDeviceComponentFilterSet, NetBoxModelFilterSet, - CableTerminationFilterSet, + CabledObjectFilterSet, PathEndpointFilterSet ): type = django_filters.MultipleChoiceFilter( @@ -1198,7 +1199,7 @@ class PowerOutletFilterSet( class InterfaceFilterSet( ModularDeviceComponentFilterSet, NetBoxModelFilterSet, - CableTerminationFilterSet, + CabledObjectFilterSet, PathEndpointFilterSet ): # Override device and device_id filters from DeviceComponentFilterSet to match against any peer virtual chassis @@ -1326,7 +1327,7 @@ class InterfaceFilterSet( class FrontPortFilterSet( ModularDeviceComponentFilterSet, NetBoxModelFilterSet, - CableTerminationFilterSet + CabledObjectFilterSet ): type = django_filters.MultipleChoiceFilter( choices=PortTypeChoices, @@ -1341,7 +1342,7 @@ class FrontPortFilterSet( class RearPortFilterSet( ModularDeviceComponentFilterSet, NetBoxModelFilterSet, - CableTerminationFilterSet + CabledObjectFilterSet ): type = django_filters.MultipleChoiceFilter( choices=PortTypeChoices, @@ -1552,6 +1553,13 @@ class CableFilterSet(TenancyFilterSet, NetBoxModelFilterSet): return queryset +class CableTerminationFilterSet(BaseFilterSet): + + class Meta: + model = CableTermination + fields = ['id', 'cable', 'cable_end', 'termination_type', 'termination_id'] + + class PowerPanelFilterSet(NetBoxModelFilterSet, ContactModelFilterSet): region_id = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), @@ -1609,7 +1617,7 @@ class PowerPanelFilterSet(NetBoxModelFilterSet, ContactModelFilterSet): return queryset.filter(qs_filter) -class PowerFeedFilterSet(NetBoxModelFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): +class PowerFeedFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet, PathEndpointFilterSet): region_id = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='power_panel__site__region', diff --git a/netbox/dcim/models/cables.py b/netbox/dcim/models/cables.py index 8090258f4..0f57bb685 100644 --- a/netbox/dcim/models/cables.py +++ b/netbox/dcim/models/cables.py @@ -13,6 +13,7 @@ from dcim.fields import PathField from dcim.utils import decompile_path_node, flatten_path, object_to_path_node, path_node_to_object from netbox.models import NetBoxModel from utilities.fields import ColorField +from utilities.querysets import RestrictedQuerySet from utilities.utils import to_meters from wireless.models import WirelessLink from .devices import Device @@ -222,6 +223,8 @@ class CableTermination(models.Model): fk_field='termination_id' ) + objects = RestrictedQuerySet.as_manager() + class Meta: ordering = ['pk'] constraints = (