diff --git a/netbox/circuits/api/serializers.py b/netbox/circuits/api/serializers.py index ab72ffcdd..6b09cd531 100644 --- a/netbox/circuits/api/serializers.py +++ b/netbox/circuits/api/serializers.py @@ -3,11 +3,11 @@ from rest_framework import serializers from circuits.choices import CircuitStatusChoices from circuits.models import * from dcim.api.nested_serializers import NestedCableSerializer, NestedSiteSerializer -from dcim.api.serializers import LinkTerminationSerializer +from dcim.api.serializers import CabledObjectSerializer from ipam.models import ASN from ipam.api.nested_serializers import NestedASNSerializer from netbox.api import ChoiceField, SerializedPKRelatedField -from netbox.api.serializers import NetBoxModelSerializer, ValidatedModelSerializer, WritableNestedSerializer +from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer from tenancy.api.nested_serializers import NestedTenantSerializer from .nested_serializers import * @@ -98,17 +98,16 @@ class CircuitSerializer(NetBoxModelSerializer): ] -class CircuitTerminationSerializer(NetBoxModelSerializer, LinkTerminationSerializer): +class CircuitTerminationSerializer(NetBoxModelSerializer, CabledObjectSerializer): url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail') circuit = NestedCircuitSerializer() site = NestedSiteSerializer(required=False, allow_null=True) provider_network = NestedProviderNetworkSerializer(required=False, allow_null=True) - cable = NestedCableSerializer(read_only=True) class Meta: model = CircuitTermination fields = [ 'id', 'url', 'display', 'circuit', 'term_side', 'site', 'provider_network', 'port_speed', 'upstream_speed', - 'xconnect_id', 'pp_info', 'description', 'mark_connected', 'cable', 'link_peers', 'link_peers_type', - '_occupied', 'tags', 'custom_fields', 'created', 'last_updated', + 'xconnect_id', 'pp_info', 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers', + 'link_peers_type', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied', ] diff --git a/netbox/circuits/models/circuits.py b/netbox/circuits/models/circuits.py index cf6ffc503..d82878cde 100644 --- a/netbox/circuits/models/circuits.py +++ b/netbox/circuits/models/circuits.py @@ -4,7 +4,7 @@ from django.db import models from django.urls import reverse from circuits.choices import * -from dcim.models import LinkTermination +from dcim.models import CabledObjectModel from netbox.models import ( ChangeLoggedModel, CustomFieldsMixin, CustomLinksMixin, OrganizationalModel, NetBoxModel, TagsMixin, ) @@ -149,7 +149,7 @@ class CircuitTermination( TagsMixin, WebhooksMixin, ChangeLoggedModel, - LinkTermination + CabledObjectModel ): circuit = models.ForeignKey( to='circuits.Circuit', diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index 57b32bfc6..9938bb2e9 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -8,7 +8,6 @@ from timezone_field.rest_framework import TimeZoneSerializerField from dcim.choices import * from dcim.constants import * from dcim.models import * -from extras.api.serializers import ContentTypeSerializer from ipam.api.nested_serializers import ( NestedASNSerializer, NestedIPAddressSerializer, NestedL2VPNTerminationSerializer, NestedVLANSerializer, NestedVRFSerializer, @@ -29,7 +28,9 @@ from wireless.models import WirelessLAN from .nested_serializers import * -class LinkTerminationSerializer(serializers.ModelSerializer): +class CabledObjectSerializer(serializers.ModelSerializer): + cable = NestedCableSerializer(read_only=True) + cable_end = serializers.CharField(read_only=True) link_peers_type = serializers.SerializerMethodField(read_only=True) link_peers = serializers.SerializerMethodField(read_only=True) _occupied = serializers.SerializerMethodField(read_only=True) @@ -67,37 +68,6 @@ class LinkTerminationSerializer(serializers.ModelSerializer): return obj._occupied -# class ConnectedEndpointSerializer(serializers.ModelSerializer): -# """ -# Legacy serializer for pre-v3.3 connections -# """ -# connected_endpoint_type = serializers.SerializerMethodField(read_only=True) -# connected_endpoint = serializers.SerializerMethodField(read_only=True) -# connected_endpoint_reachable = serializers.SerializerMethodField(read_only=True) -# -# def get_connected_endpoint_type(self, obj): -# if obj._path is not None and obj._path.destination is not None: -# return f'{obj._path.destination._meta.app_label}.{obj._path.destination._meta.model_name}' -# return None -# -# @swagger_serializer_method(serializer_or_field=serializers.DictField) -# def get_connected_endpoint(self, obj): -# """ -# Return the appropriate serializer for the type of connected object. -# """ -# if obj._path is not None and obj._path.destination is not None: -# serializer = get_serializer_for_model(obj._path.destination, prefix='Nested') -# context = {'request': self.context['request']} -# return serializer(obj._path.destination, context=context).data -# return None -# -# @swagger_serializer_method(serializer_or_field=serializers.BooleanField) -# def get_connected_endpoint_reachable(self, obj): -# if obj._path is not None: -# return obj._path.is_active -# return None - - class ConnectedEndpointsSerializer(serializers.ModelSerializer): """ Legacy serializer for pre-v3.3 connections @@ -729,7 +699,7 @@ class DeviceNAPALMSerializer(serializers.Serializer): # Device components # -class ConsoleServerPortSerializer(NetBoxModelSerializer, LinkTerminationSerializer, ConnectedEndpointsSerializer): +class ConsoleServerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverport-detail') device = NestedDeviceSerializer() module = ComponentNestedModuleSerializer( @@ -746,18 +716,18 @@ class ConsoleServerPortSerializer(NetBoxModelSerializer, LinkTerminationSerializ allow_null=True, required=False ) - cable = NestedCableSerializer(read_only=True) class Meta: model = ConsoleServerPort fields = [ 'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'speed', 'description', - 'mark_connected', 'cable', 'link_peers', 'link_peers_type', 'connected_endpoints', 'connected_endpoints_type', - 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied', + 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', 'connected_endpoints', + 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created', + 'last_updated', '_occupied', ] -class ConsolePortSerializer(NetBoxModelSerializer, LinkTerminationSerializer, ConnectedEndpointsSerializer): +class ConsolePortSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleport-detail') device = NestedDeviceSerializer() module = ComponentNestedModuleSerializer( @@ -774,18 +744,18 @@ class ConsolePortSerializer(NetBoxModelSerializer, LinkTerminationSerializer, Co allow_null=True, required=False ) - cable = NestedCableSerializer(read_only=True) class Meta: model = ConsolePort fields = [ 'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'speed', 'description', - 'mark_connected', 'cable', 'link_peers', 'link_peers_type', 'connected_endpoints', 'connected_endpoints_type', - 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied', + 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', 'connected_endpoints', + 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created', + 'last_updated', '_occupied', ] -class PowerOutletSerializer(NetBoxModelSerializer, LinkTerminationSerializer, ConnectedEndpointsSerializer): +class PowerOutletSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlet-detail') device = NestedDeviceSerializer() module = ComponentNestedModuleSerializer( @@ -806,21 +776,18 @@ class PowerOutletSerializer(NetBoxModelSerializer, LinkTerminationSerializer, Co allow_blank=True, required=False ) - cable = NestedCableSerializer( - read_only=True - ) class Meta: model = PowerOutlet fields = [ 'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'power_port', 'feed_leg', - 'description', 'mark_connected', 'cable', 'link_peers', 'link_peers_type', 'connected_endpoints', - 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created', - 'last_updated', '_occupied', + 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', + 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', + 'created', 'last_updated', '_occupied', ] -class PowerPortSerializer(NetBoxModelSerializer, LinkTerminationSerializer, ConnectedEndpointsSerializer): +class PowerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerport-detail') device = NestedDeviceSerializer() module = ComponentNestedModuleSerializer( @@ -832,19 +799,18 @@ class PowerPortSerializer(NetBoxModelSerializer, LinkTerminationSerializer, Conn allow_blank=True, required=False ) - cable = NestedCableSerializer(read_only=True) class Meta: model = PowerPort fields = [ 'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', - 'description', 'mark_connected', 'cable', 'link_peers', 'link_peers_type', 'connected_endpoints', - 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created', - 'last_updated', '_occupied', + 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', + 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', + 'created', 'last_updated', '_occupied', ] -class InterfaceSerializer(NetBoxModelSerializer, LinkTerminationSerializer, ConnectedEndpointsSerializer): +class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail') device = NestedDeviceSerializer() module = ComponentNestedModuleSerializer( @@ -870,7 +836,6 @@ class InterfaceSerializer(NetBoxModelSerializer, LinkTerminationSerializer, Conn ) vrf = NestedVRFSerializer(required=False, allow_null=True) l2vpn_termination = NestedL2VPNTerminationSerializer(read_only=True) - cable = NestedCableSerializer(read_only=True) wireless_link = NestedWirelessLinkSerializer(read_only=True) wireless_lans = SerializedPKRelatedField( queryset=WirelessLAN.objects.all(), @@ -887,7 +852,7 @@ class InterfaceSerializer(NetBoxModelSerializer, LinkTerminationSerializer, Conn 'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'enabled', 'parent', 'bridge', 'lag', 'mtu', 'mac_address', 'speed', 'duplex', 'wwn', 'mgmt_only', 'description', 'mode', 'rf_role', 'rf_channel', 'poe_mode', 'poe_type', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'untagged_vlan', - 'tagged_vlans', 'mark_connected', 'cable', 'wireless_link', 'link_peers', 'link_peers_type', + 'tagged_vlans', 'mark_connected', 'cable', 'cable_end', 'wireless_link', 'link_peers', 'link_peers_type', 'wireless_lans', 'vrf', 'l2vpn_termination', 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created', 'last_updated', 'count_ipaddresses', 'count_fhrp_groups', '_occupied', @@ -907,7 +872,7 @@ class InterfaceSerializer(NetBoxModelSerializer, LinkTerminationSerializer, Conn return super().validate(data) -class RearPortSerializer(NetBoxModelSerializer, LinkTerminationSerializer): +class RearPortSerializer(NetBoxModelSerializer, CabledObjectSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearport-detail') device = NestedDeviceSerializer() module = ComponentNestedModuleSerializer( @@ -915,13 +880,12 @@ class RearPortSerializer(NetBoxModelSerializer, LinkTerminationSerializer): allow_null=True ) type = ChoiceField(choices=PortTypeChoices) - cable = NestedCableSerializer(read_only=True) class Meta: model = RearPort fields = [ 'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'color', 'positions', 'description', - 'mark_connected', 'cable', 'link_peers', 'link_peers_type', 'tags', 'custom_fields', 'created', + 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied', ] @@ -937,7 +901,7 @@ class FrontPortRearPortSerializer(WritableNestedSerializer): fields = ['id', 'url', 'display', 'name', 'label'] -class FrontPortSerializer(NetBoxModelSerializer, LinkTerminationSerializer): +class FrontPortSerializer(NetBoxModelSerializer, CabledObjectSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:frontport-detail') device = NestedDeviceSerializer() module = ComponentNestedModuleSerializer( @@ -946,14 +910,13 @@ class FrontPortSerializer(NetBoxModelSerializer, LinkTerminationSerializer): ) type = ChoiceField(choices=PortTypeChoices) rear_port = FrontPortRearPortSerializer() - cable = NestedCableSerializer(read_only=True) class Meta: model = FrontPort fields = [ 'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'color', 'rear_port', - 'rear_port_position', 'description', 'mark_connected', 'cable', 'link_peers', 'link_peers_type', 'tags', - 'custom_fields', 'created', 'last_updated', '_occupied', + 'rear_port_position', 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers', + 'link_peers_type', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied', ] @@ -1204,7 +1167,7 @@ class PowerPanelSerializer(NetBoxModelSerializer): ] -class PowerFeedSerializer(NetBoxModelSerializer, LinkTerminationSerializer, ConnectedEndpointsSerializer): +class PowerFeedSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerfeed-detail') power_panel = NestedPowerPanelSerializer() rack = NestedRackSerializer( @@ -1228,13 +1191,12 @@ class PowerFeedSerializer(NetBoxModelSerializer, LinkTerminationSerializer, Conn choices=PowerFeedPhaseChoices, default=PowerFeedPhaseChoices.PHASE_SINGLE ) - cable = NestedCableSerializer(read_only=True) class Meta: model = PowerFeed fields = [ 'id', 'url', 'display', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage', - 'amperage', 'max_utilization', 'comments', 'mark_connected', 'cable', 'link_peers', 'link_peers_type', - 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', - 'created', 'last_updated', '_occupied', + 'amperage', 'max_utilization', 'comments', 'mark_connected', 'cable', 'cable_end', 'link_peers', + 'link_peers_type', 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', + 'tags', 'custom_fields', 'created', 'last_updated', '_occupied', ] diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index 67af3a7f8..d54ad8384 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -3,7 +3,7 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models -from django.db.models import Q, Sum +from django.db.models import Sum from django.urls import reverse from mptt.models import MPTTModel, TreeForeignKey @@ -23,7 +23,7 @@ from wireless.utils import get_channel_attr __all__ = ( 'BaseInterface', - 'LinkTermination', + 'CabledObjectModel', 'ConsolePort', 'ConsoleServerPort', 'DeviceBay', @@ -103,7 +103,7 @@ class ModularComponentModel(ComponentModel): abstract = True -class LinkTermination(models.Model): +class CabledObjectModel(models.Model): """ An abstract model inherited by all models to which a Cable can terminate. """ @@ -237,7 +237,7 @@ class PathEndpoint(models.Model): # Console components # -class ConsolePort(ModularComponentModel, LinkTermination, PathEndpoint): +class ConsolePort(ModularComponentModel, CabledObjectModel, PathEndpoint): """ A physical console port within a Device. ConsolePorts connect to ConsoleServerPorts. """ @@ -264,7 +264,7 @@ class ConsolePort(ModularComponentModel, LinkTermination, PathEndpoint): return reverse('dcim:consoleport', kwargs={'pk': self.pk}) -class ConsoleServerPort(ModularComponentModel, LinkTermination, PathEndpoint): +class ConsoleServerPort(ModularComponentModel, CabledObjectModel, PathEndpoint): """ A physical port within a Device (typically a designated console server) which provides access to ConsolePorts. """ @@ -295,7 +295,7 @@ class ConsoleServerPort(ModularComponentModel, LinkTermination, PathEndpoint): # Power components # -class PowerPort(ModularComponentModel, LinkTermination, PathEndpoint): +class PowerPort(ModularComponentModel, CabledObjectModel, PathEndpoint): """ A physical power supply (intake) port within a Device. PowerPorts connect to PowerOutlets. """ @@ -400,7 +400,7 @@ class PowerPort(ModularComponentModel, LinkTermination, PathEndpoint): } -class PowerOutlet(ModularComponentModel, LinkTermination, PathEndpoint): +class PowerOutlet(ModularComponentModel, CabledObjectModel, PathEndpoint): """ A physical power outlet (output) within a Device which provides power to a PowerPort. """ @@ -512,7 +512,7 @@ class BaseInterface(models.Model): return self.fhrp_group_assignments.count() -class Interface(ModularComponentModel, BaseInterface, LinkTermination, PathEndpoint): +class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEndpoint): """ A network interface within a Device. A physical Interface can connect to exactly one other Interface. """ @@ -837,7 +837,7 @@ class Interface(ModularComponentModel, BaseInterface, LinkTermination, PathEndpo # Pass-through ports # -class FrontPort(ModularComponentModel, LinkTermination): +class FrontPort(ModularComponentModel, CabledObjectModel): """ A pass-through port on the front of a Device. """ @@ -890,7 +890,7 @@ class FrontPort(ModularComponentModel, LinkTermination): }) -class RearPort(ModularComponentModel, LinkTermination): +class RearPort(ModularComponentModel, CabledObjectModel): """ A pass-through port on the rear of a Device. """ diff --git a/netbox/dcim/models/power.py b/netbox/dcim/models/power.py index 5978d86bd..94767c6c4 100644 --- a/netbox/dcim/models/power.py +++ b/netbox/dcim/models/power.py @@ -9,7 +9,7 @@ from dcim.constants import * from netbox.config import ConfigItem from netbox.models import NetBoxModel from utilities.validators import ExclusionValidator -from .device_components import LinkTermination, PathEndpoint +from .device_components import CabledObjectModel, PathEndpoint __all__ = ( 'PowerFeed', @@ -67,7 +67,7 @@ class PowerPanel(NetBoxModel): ) -class PowerFeed(NetBoxModel, PathEndpoint, LinkTermination): +class PowerFeed(NetBoxModel, PathEndpoint, CabledObjectModel): """ An electrical circuit delivered from a PowerPanel. """