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

Implemented Cable API endpoint

Jeremy Stretch 7 лет назад
Родитель
Сommit
3518d023dc
4 измененных файлов с 64 добавлено и 6 удалено
  1. 48 5
      netbox/dcim/api/serializers.py
  2. 3 0
      netbox/dcim/api/urls.py
  3. 11 1
      netbox/dcim/api/views.py
  4. 2 0
      netbox/utilities/api.py

+ 48 - 5
netbox/dcim/api/serializers.py

@@ -5,7 +5,7 @@ from taggit_serializer.serializers import TaggitSerializer, TagListSerializerFie
 from circuits.models import Circuit, CircuitTermination
 from dcim.constants import *
 from dcim.models import (
-    ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
+    Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
     DeviceBayTemplate, DeviceType, DeviceRole, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
     Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack,
     RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site, VirtualChassis,
@@ -15,8 +15,8 @@ from ipam.models import IPAddress, VLAN
 from tenancy.api.serializers import NestedTenantSerializer
 from users.api.serializers import NestedUserSerializer
 from utilities.api import (
-    ChoiceField, SerializedPKRelatedField, TimeZoneField, ValidatedModelSerializer,
-    WritableNestedSerializer,
+    ChoiceField, ContentTypeField, SerializedPKRelatedField, TimeZoneField, ValidatedModelSerializer,
+    WritableNestedSerializer, get_serializer_for_model,
 )
 from virtualization.models import Cluster
 
@@ -717,11 +717,12 @@ class RearPortSerializer(ValidatedModelSerializer):
 
 
 class NestedRearPortSerializer(WritableNestedSerializer):
+    device = NestedDeviceSerializer(read_only=True)
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearport-detail')
 
     class Meta:
         model = RearPort
-        fields = ['id', 'url', 'name']
+        fields = ['id', 'url', 'device', 'name']
 
 
 #
@@ -740,11 +741,12 @@ class FrontPortSerializer(ValidatedModelSerializer):
 
 
 class NestedFrontPortSerializer(WritableNestedSerializer):
+    device = NestedDeviceSerializer(read_only=True)
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:frontport-detail')
 
     class Meta:
         model = FrontPort
-        fields = ['id', 'url', 'name']
+        fields = ['id', 'url', 'device', 'name']
 
 
 #
@@ -807,6 +809,47 @@ class InterfaceConnectionSerializer(ValidatedModelSerializer):
         return NestedInterfaceSerializer(instance=obj, context=context).data
 
 
+#
+# Cables
+#
+
+class CableSerializer(ValidatedModelSerializer):
+    termination_a_type = ContentTypeField()
+    termination_b_type = ContentTypeField()
+    termination_a = serializers.SerializerMethodField(read_only=True)
+    termination_b = serializers.SerializerMethodField(read_only=True)
+    status = ChoiceField(choices=CONNECTION_STATUS_CHOICES)
+    length_unit = ChoiceField(choices=LENGTH_UNIT_CHOICES)
+
+    class Meta:
+        model = Cable
+        fields = [
+            'id', 'termination_a_type', 'termination_a_id', 'termination_a', 'termination_b_type', 'termination_b_id',
+            'termination_b', 'type', 'status', 'label', 'color', 'length', 'length_unit',
+        ]
+
+    def _get_termination(self, obj, side):
+        """
+        Serialize a nested representation of a termination.
+        """
+        if side.lower() not in ['a', 'b']:
+            raise ValueError("Termination side must be either A or B.")
+        termination = getattr(obj, 'termination_{}'.format(side.lower()))
+        if termination is None:
+            return None
+        serializer = get_serializer_for_model(termination, prefix='Nested')
+        context = {'request': self.context['request']}
+        data = serializer(termination, context=context).data
+
+        return data
+
+    def get_termination_a(self, obj):
+        return self._get_termination(obj, 'a')
+
+    def get_termination_b(self, obj):
+        return self._get_termination(obj, 'b')
+
+
 #
 # Virtual chassis
 #

+ 3 - 0
netbox/dcim/api/urls.py

@@ -62,6 +62,9 @@ router.register(r'console-connections', views.ConsoleConnectionViewSet, base_nam
 router.register(r'power-connections', views.PowerConnectionViewSet, base_name='powerconnections')
 router.register(r'interface-connections', views.InterfaceConnectionViewSet, base_name='interfaceconnections')
 
+# Cables
+router.register(r'cables', views.CableViewSet)
+
 # Virtual chassis
 router.register(r'virtual-chassis', views.VirtualChassisViewSet)
 

+ 11 - 1
netbox/dcim/api/views.py

@@ -14,7 +14,7 @@ from rest_framework.viewsets import GenericViewSet, ViewSet
 
 from dcim import filters
 from dcim.models import (
-    ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
+    Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
     DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
     Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack,
     RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site, VirtualChassis,
@@ -428,6 +428,16 @@ class InterfaceConnectionViewSet(ModelViewSet):
     filter_class = filters.InterfaceConnectionFilter
 
 
+#
+# Cables
+#
+
+class CableViewSet(ModelViewSet):
+    queryset = Cable.objects.prefetch_related('termination_a__device', 'termination_b__device')
+    serializer_class = serializers.CableSerializer
+    filter_class = filters.CableFilter
+
+
 #
 # Virtual chassis
 #

+ 2 - 0
netbox/utilities/api.py

@@ -69,6 +69,8 @@ class ChoiceField(Field):
         super(ChoiceField, self).__init__(**kwargs)
 
     def to_representation(self, obj):
+        if obj is '':
+            return None
         return {'value': obj, 'label': self._choices[obj]}
 
     def to_internal_value(self, data):