Bläddra i källkod

Add modules to device component serializers

jeremystretch 4 år sedan
förälder
incheckning
ed6a160372
3 ändrade filer med 90 tillägg och 30 borttagningar
  1. 22 2
      netbox/dcim/api/nested_serializers.py
  2. 50 20
      netbox/dcim/api/serializers.py
  3. 18 8
      netbox/dcim/api/views.py

+ 22 - 2
netbox/dcim/api/nested_serializers.py

@@ -4,6 +4,7 @@ from dcim import models
 from netbox.api.serializers import BaseModelSerializer, WritableNestedSerializer
 
 __all__ = [
+    'ComponentNestedModuleSerializer',
     'NestedCableSerializer',
     'NestedConsolePortSerializer',
     'NestedConsolePortTemplateSerializer',
@@ -261,11 +262,30 @@ class NestedDeviceSerializer(WritableNestedSerializer):
         fields = ['id', 'url', 'display', 'name']
 
 
+class ModuleNestedModuleBaySerializer(WritableNestedSerializer):
+    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:modulebay-detail')
+
+    class Meta:
+        model = models.ModuleBay
+        fields = ['id', 'url', 'display', 'name']
+
+
+class ComponentNestedModuleSerializer(WritableNestedSerializer):
+    """
+    Used by device component serializers.
+    """
+    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')
+    module_bay = ModuleNestedModuleBaySerializer(read_only=True)
+
+    class Meta:
+        model = models.Module
+        fields = ['id', 'url', 'display', 'device', 'module_bay']
+
+
 class NestedModuleSerializer(WritableNestedSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')
     device = NestedDeviceSerializer(read_only=True)
-    # TODO: Solve circular dependency
-    # module_bay = NestedModuleBaySerializer(read_only=True)
+    module_bay = ModuleNestedModuleBaySerializer(read_only=True)
     module_type = NestedModuleTypeSerializer(read_only=True)
 
     class Meta:

+ 50 - 20
netbox/dcim/api/serializers.py

@@ -558,6 +558,10 @@ class DeviceNAPALMSerializer(serializers.Serializer):
 class ConsoleServerPortSerializer(PrimaryModelSerializer, LinkTerminationSerializer, ConnectedEndpointSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverport-detail')
     device = NestedDeviceSerializer()
+    module = ComponentNestedModuleSerializer(
+        required=False,
+        allow_null=True
+    )
     type = ChoiceField(
         choices=ConsolePortTypeChoices,
         allow_blank=True,
@@ -573,8 +577,8 @@ class ConsoleServerPortSerializer(PrimaryModelSerializer, LinkTerminationSeriali
     class Meta:
         model = ConsoleServerPort
         fields = [
-            'id', 'url', 'display', 'device', 'name', 'label', 'type', 'speed', 'description', 'mark_connected',
-            'cable', 'link_peer', 'link_peer_type', 'connected_endpoint', 'connected_endpoint_type',
+            'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'speed', 'description',
+            'mark_connected', 'cable', 'link_peer', 'link_peer_type', 'connected_endpoint', 'connected_endpoint_type',
             'connected_endpoint_reachable', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
         ]
 
@@ -582,6 +586,10 @@ class ConsoleServerPortSerializer(PrimaryModelSerializer, LinkTerminationSeriali
 class ConsolePortSerializer(PrimaryModelSerializer, LinkTerminationSerializer, ConnectedEndpointSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleport-detail')
     device = NestedDeviceSerializer()
+    module = ComponentNestedModuleSerializer(
+        required=False,
+        allow_null=True
+    )
     type = ChoiceField(
         choices=ConsolePortTypeChoices,
         allow_blank=True,
@@ -597,8 +605,8 @@ class ConsolePortSerializer(PrimaryModelSerializer, LinkTerminationSerializer, C
     class Meta:
         model = ConsolePort
         fields = [
-            'id', 'url', 'display', 'device', 'name', 'label', 'type', 'speed', 'description', 'mark_connected',
-            'cable', 'link_peer', 'link_peer_type', 'connected_endpoint', 'connected_endpoint_type',
+            'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'speed', 'description',
+            'mark_connected', 'cable', 'link_peer', 'link_peer_type', 'connected_endpoint', 'connected_endpoint_type',
             'connected_endpoint_reachable', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
         ]
 
@@ -606,6 +614,10 @@ class ConsolePortSerializer(PrimaryModelSerializer, LinkTerminationSerializer, C
 class PowerOutletSerializer(PrimaryModelSerializer, LinkTerminationSerializer, ConnectedEndpointSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlet-detail')
     device = NestedDeviceSerializer()
+    module = ComponentNestedModuleSerializer(
+        required=False,
+        allow_null=True
+    )
     type = ChoiceField(
         choices=PowerOutletTypeChoices,
         allow_blank=True,
@@ -627,15 +639,20 @@ class PowerOutletSerializer(PrimaryModelSerializer, LinkTerminationSerializer, C
     class Meta:
         model = PowerOutlet
         fields = [
-            'id', 'url', 'display', 'device', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description',
-            'mark_connected', 'cable', 'link_peer', 'link_peer_type', 'connected_endpoint', 'connected_endpoint_type',
-            'connected_endpoint_reachable', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
+            'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'power_port', 'feed_leg',
+            'description', 'mark_connected', 'cable', 'link_peer', 'link_peer_type', 'connected_endpoint',
+            'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields', 'created',
+            'last_updated', '_occupied',
         ]
 
 
 class PowerPortSerializer(PrimaryModelSerializer, LinkTerminationSerializer, ConnectedEndpointSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerport-detail')
     device = NestedDeviceSerializer()
+    module = ComponentNestedModuleSerializer(
+        required=False,
+        allow_null=True
+    )
     type = ChoiceField(
         choices=PowerPortTypeChoices,
         allow_blank=True,
@@ -646,15 +663,20 @@ class PowerPortSerializer(PrimaryModelSerializer, LinkTerminationSerializer, Con
     class Meta:
         model = PowerPort
         fields = [
-            'id', 'url', 'display', 'device', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description',
-            'mark_connected', 'cable', 'link_peer', 'link_peer_type', 'connected_endpoint', 'connected_endpoint_type',
-            'connected_endpoint_reachable', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
+            'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw',
+            'description', 'mark_connected', 'cable', 'link_peer', 'link_peer_type', 'connected_endpoint',
+            'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields', 'created',
+            'last_updated', '_occupied',
         ]
 
 
 class InterfaceSerializer(PrimaryModelSerializer, LinkTerminationSerializer, ConnectedEndpointSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
     device = NestedDeviceSerializer()
+    module = ComponentNestedModuleSerializer(
+        required=False,
+        allow_null=True
+    )
     type = ChoiceField(choices=InterfaceTypeChoices)
     parent = NestedInterfaceSerializer(required=False, allow_null=True)
     bridge = NestedInterfaceSerializer(required=False, allow_null=True)
@@ -683,12 +705,12 @@ class InterfaceSerializer(PrimaryModelSerializer, LinkTerminationSerializer, Con
     class Meta:
         model = Interface
         fields = [
-            'id', 'url', 'display', 'device', 'name', 'label', 'type', 'enabled', 'parent', 'bridge', 'lag', 'mtu',
-            'mac_address', 'wwn', 'mgmt_only', 'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency',
-            'rf_channel_width', 'tx_power', 'untagged_vlan', 'tagged_vlans', 'mark_connected', 'cable', 'wireless_link',
-            'link_peer', 'link_peer_type', 'wireless_lans', 'connected_endpoint', 'connected_endpoint_type',
-            'connected_endpoint_reachable', 'tags', 'custom_fields', 'created', 'last_updated', 'count_ipaddresses',
-            'count_fhrp_groups', '_occupied',
+            'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'enabled', 'parent', 'bridge', 'lag',
+            'mtu', 'mac_address', 'wwn', 'mgmt_only', 'description', 'mode', 'rf_role', 'rf_channel',
+            'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'untagged_vlan', 'tagged_vlans', 'mark_connected',
+            'cable', 'wireless_link', 'link_peer', 'link_peer_type', 'wireless_lans', 'connected_endpoint',
+            'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields', 'created',
+            'last_updated', 'count_ipaddresses', 'count_fhrp_groups', '_occupied',
         ]
 
     def validate(self, data):
@@ -708,13 +730,17 @@ class InterfaceSerializer(PrimaryModelSerializer, LinkTerminationSerializer, Con
 class RearPortSerializer(PrimaryModelSerializer, LinkTerminationSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearport-detail')
     device = NestedDeviceSerializer()
+    module = ComponentNestedModuleSerializer(
+        required=False,
+        allow_null=True
+    )
     type = ChoiceField(choices=PortTypeChoices)
     cable = NestedCableSerializer(read_only=True)
 
     class Meta:
         model = RearPort
         fields = [
-            'id', 'url', 'display', 'device', 'name', 'label', 'type', 'color', 'positions', 'description',
+            'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'color', 'positions', 'description',
             'mark_connected', 'cable', 'link_peer', 'link_peer_type', 'tags', 'custom_fields', 'created',
             'last_updated', '_occupied',
         ]
@@ -734,6 +760,10 @@ class FrontPortRearPortSerializer(WritableNestedSerializer):
 class FrontPortSerializer(PrimaryModelSerializer, LinkTerminationSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:frontport-detail')
     device = NestedDeviceSerializer()
+    module = ComponentNestedModuleSerializer(
+        required=False,
+        allow_null=True
+    )
     type = ChoiceField(choices=PortTypeChoices)
     rear_port = FrontPortRearPortSerializer()
     cable = NestedCableSerializer(read_only=True)
@@ -741,9 +771,9 @@ class FrontPortSerializer(PrimaryModelSerializer, LinkTerminationSerializer):
     class Meta:
         model = FrontPort
         fields = [
-            'id', 'url', 'display', 'device', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position',
-            'description', 'mark_connected', 'cable', 'link_peer', 'link_peer_type', 'tags', 'custom_fields',
-            'created', 'last_updated', '_occupied',
+            'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'color', 'rear_port',
+            'rear_port_position', 'description', 'mark_connected', 'cable', 'link_peer', 'link_peer_type', 'tags',
+            'custom_fields', 'created', 'last_updated', '_occupied',
         ]
 
 

+ 18 - 8
netbox/dcim/api/views.py

@@ -539,7 +539,9 @@ class ModuleViewSet(CustomFieldModelViewSet):
 #
 
 class ConsolePortViewSet(PathEndpointMixin, ModelViewSet):
-    queryset = ConsolePort.objects.prefetch_related('device', '_path__destination', 'cable', '_link_peer', 'tags')
+    queryset = ConsolePort.objects.prefetch_related(
+        'device', 'module__module_bay', '_path__destination', 'cable', '_link_peer', 'tags'
+    )
     serializer_class = serializers.ConsolePortSerializer
     filterset_class = filtersets.ConsolePortFilterSet
     brief_prefetch_fields = ['device']
@@ -547,7 +549,7 @@ class ConsolePortViewSet(PathEndpointMixin, ModelViewSet):
 
 class ConsoleServerPortViewSet(PathEndpointMixin, ModelViewSet):
     queryset = ConsoleServerPort.objects.prefetch_related(
-        'device', '_path__destination', 'cable', '_link_peer', 'tags'
+        'device', 'module__module_bay', '_path__destination', 'cable', '_link_peer', 'tags'
     )
     serializer_class = serializers.ConsoleServerPortSerializer
     filterset_class = filtersets.ConsoleServerPortFilterSet
@@ -555,14 +557,18 @@ class ConsoleServerPortViewSet(PathEndpointMixin, ModelViewSet):
 
 
 class PowerPortViewSet(PathEndpointMixin, ModelViewSet):
-    queryset = PowerPort.objects.prefetch_related('device', '_path__destination', 'cable', '_link_peer', 'tags')
+    queryset = PowerPort.objects.prefetch_related(
+        'device', 'module__module_bay', '_path__destination', 'cable', '_link_peer', 'tags'
+    )
     serializer_class = serializers.PowerPortSerializer
     filterset_class = filtersets.PowerPortFilterSet
     brief_prefetch_fields = ['device']
 
 
 class PowerOutletViewSet(PathEndpointMixin, ModelViewSet):
-    queryset = PowerOutlet.objects.prefetch_related('device', '_path__destination', 'cable', '_link_peer', 'tags')
+    queryset = PowerOutlet.objects.prefetch_related(
+        'device', 'module__module_bay', '_path__destination', 'cable', '_link_peer', 'tags'
+    )
     serializer_class = serializers.PowerOutletSerializer
     filterset_class = filtersets.PowerOutletFilterSet
     brief_prefetch_fields = ['device']
@@ -570,8 +576,8 @@ class PowerOutletViewSet(PathEndpointMixin, ModelViewSet):
 
 class InterfaceViewSet(PathEndpointMixin, ModelViewSet):
     queryset = Interface.objects.prefetch_related(
-        'device', 'parent', 'bridge', 'lag', '_path__destination', 'cable', '_link_peer', 'wireless_lans',
-        'untagged_vlan', 'tagged_vlans', 'ip_addresses', 'fhrp_group_assignments', 'tags'
+        'device', 'module__module_bay', 'parent', 'bridge', 'lag', '_path__destination', 'cable', '_link_peer',
+        'wireless_lans', 'untagged_vlan', 'tagged_vlans', 'ip_addresses', 'fhrp_group_assignments', 'tags'
     )
     serializer_class = serializers.InterfaceSerializer
     filterset_class = filtersets.InterfaceFilterSet
@@ -579,14 +585,18 @@ class InterfaceViewSet(PathEndpointMixin, ModelViewSet):
 
 
 class FrontPortViewSet(PassThroughPortMixin, ModelViewSet):
-    queryset = FrontPort.objects.prefetch_related('device__device_type__manufacturer', 'rear_port', 'cable', 'tags')
+    queryset = FrontPort.objects.prefetch_related(
+        'device__device_type__manufacturer', 'module__module_bay', 'rear_port', 'cable', 'tags'
+    )
     serializer_class = serializers.FrontPortSerializer
     filterset_class = filtersets.FrontPortFilterSet
     brief_prefetch_fields = ['device']
 
 
 class RearPortViewSet(PassThroughPortMixin, ModelViewSet):
-    queryset = RearPort.objects.prefetch_related('device__device_type__manufacturer', 'cable', 'tags')
+    queryset = RearPort.objects.prefetch_related(
+        'device__device_type__manufacturer', 'module__module_bay', 'cable', 'tags'
+    )
     serializer_class = serializers.RearPortSerializer
     filterset_class = filtersets.RearPortFilterSet
     brief_prefetch_fields = ['device']