Coverage for dcim/api/serializers_/cables.py: 75%
79 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1from drf_spectacular.types import OpenApiTypes
2from drf_spectacular.utils import extend_schema_field
3from rest_framework import serializers
5from dcim.choices import *
6from dcim.models import Cable, CableBundle, CablePath, CableTermination
7from netbox.api.fields import ChoiceField, ContentTypeField
8from netbox.api.gfk_fields import GFKSerializerField
9from netbox.api.serializers import (
10 BaseModelSerializer,
11 GenericObjectSerializer,
12 NetBoxModelSerializer,
13 PrimaryModelSerializer,
14)
15from tenancy.api.serializers_.tenants import TenantSerializer
16from utilities.api import get_serializer_for_model
18__all__ = (
19 'CableBundleSerializer',
20 'CablePathSerializer',
21 'CableSerializer',
22 'CableTerminationSerializer',
23 'CabledObjectSerializer',
24 'TracedCableSerializer',
25)
28class CableBundleSerializer(PrimaryModelSerializer):
29 cable_count = serializers.IntegerField(read_only=True, default=0)
31 class Meta:
32 model = CableBundle
33 fields = [
34 'id', 'url', 'display_url', 'display', 'name', 'description', 'owner', 'comments', 'tags',
35 'custom_fields', 'created', 'last_updated', 'cable_count',
36 ]
37 brief_fields = ('id', 'url', 'display', 'name', 'description')
40class CableSerializer(PrimaryModelSerializer):
41 a_terminations = GenericObjectSerializer(many=True, required=False)
42 b_terminations = GenericObjectSerializer(many=True, required=False)
43 status = ChoiceField(choices=LinkStatusChoices, required=False)
44 profile = ChoiceField(choices=CableProfileChoices, required=False)
45 tenant = TenantSerializer(nested=True, required=False, allow_null=True)
46 length_unit = ChoiceField(choices=CableLengthUnitChoices, allow_blank=True, required=False, allow_null=True)
47 bundle = CableBundleSerializer(nested=True, required=False, allow_null=True, default=None)
49 class Meta:
50 model = Cable
51 fields = [
52 'id', 'url', 'display_url', 'display', 'type', 'a_terminations', 'b_terminations', 'status', 'profile',
53 'tenant', 'bundle', 'label', 'color', 'length', 'length_unit', 'description', 'owner', 'comments', 'tags',
54 'custom_fields', 'created', 'last_updated',
55 ]
56 brief_fields = ('id', 'url', 'display', 'label', 'description')
59class TracedCableSerializer(BaseModelSerializer):
60 """
61 Used only while tracing a cable path.
62 """
64 class Meta:
65 model = Cable
66 fields = [
67 'id', 'url', 'display_url', 'type', 'status', 'label', 'color', 'length', 'length_unit', 'description',
68 ]
71class CableTerminationSerializer(NetBoxModelSerializer):
72 termination_type = ContentTypeField(
73 read_only=True,
74 )
75 termination = GFKSerializerField(read_only=True)
77 class Meta:
78 model = CableTermination
79 fields = [
80 'id', 'url', 'display', 'cable', 'cable_end', 'termination_type', 'termination_id',
81 'termination', 'connector', 'positions', 'created', 'last_updated',
82 ]
83 read_only_fields = fields
84 brief_fields = (
85 'id', 'url', 'display', 'cable', 'cable_end', 'connector', 'positions', 'termination_type',
86 'termination_id',
87 )
90class CablePathSerializer(serializers.ModelSerializer):
91 path = serializers.SerializerMethodField(read_only=True)
93 class Meta:
94 model = CablePath
95 fields = ['id', 'path', 'is_active', 'is_complete', 'is_split']
97 @extend_schema_field(serializers.ListField)
98 def get_path(self, obj):
99 ret = []
100 for nodes in obj.path_objects:
101 if not nodes:
102 # The path contains an invalid object
103 return []
104 serializer = get_serializer_for_model(nodes[0])
105 context = {'request': self.context['request']}
106 ret.append(serializer(nodes, nested=True, many=True, context=context).data)
107 return ret
110class CabledObjectSerializer(serializers.ModelSerializer):
111 cable = CableSerializer(nested=True, read_only=True, allow_null=True)
112 # Use DRF's ChoiceField; NetBox's ChoiceField would return a value/label object.
113 cable_end = serializers.ChoiceField(choices=CableEndChoices, read_only=True, allow_null=True)
114 link_peers_type = serializers.SerializerMethodField(read_only=True, allow_null=True)
115 link_peers = serializers.SerializerMethodField(read_only=True)
116 _occupied = serializers.SerializerMethodField(read_only=True)
118 @extend_schema_field(OpenApiTypes.STR)
119 def get_link_peers_type(self, obj):
120 """
121 Return the type of the peer link terminations, or None.
122 """
123 if not obj.cable: 123 ↛ 126line 123 didn't jump to line 126 because the condition on line 123 was always true
124 return None
126 if obj.link_peers:
127 return f'{obj.link_peers[0]._meta.app_label}.{obj.link_peers[0]._meta.model_name}'
129 return None
131 @extend_schema_field(serializers.ListField)
132 def get_link_peers(self, obj):
133 """
134 Return the appropriate serializer for the link termination model.
135 """
136 if not obj.link_peers: 136 ↛ 140line 136 didn't jump to line 140 because the condition on line 136 was always true
137 return []
139 # Return serialized peer termination objects
140 serializer = get_serializer_for_model(obj.link_peers[0])
141 context = {'request': self.context['request']}
142 return serializer(obj.link_peers, nested=True, many=True, context=context).data
144 @extend_schema_field(serializers.BooleanField)
145 def get__occupied(self, obj):
146 return obj._occupied