Browse Source

Introduced WritableSerializerMixin

Jeremy Stretch 8 years ago
parent
commit
12d263999b

+ 6 - 8
netbox/circuits/api/views.py

@@ -9,6 +9,7 @@ from circuits.models import Provider, CircuitTermination, CircuitType, Circuit
 from circuits.filters import CircuitFilter
 from circuits.filters import CircuitFilter
 
 
 from extras.api.views import CustomFieldModelViewSet
 from extras.api.views import CustomFieldModelViewSet
+from utilities.api import WritableSerializerMixin
 from . import serializers
 from . import serializers
 
 
 
 
@@ -34,26 +35,23 @@ class CircuitTypeViewSet(ModelViewSet):
 # Circuits
 # Circuits
 #
 #
 
 
-class CircuitViewSet(CustomFieldModelViewSet):
+class CircuitViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
     queryset = Circuit.objects.select_related('type', 'tenant', 'provider')
     queryset = Circuit.objects.select_related('type', 'tenant', 'provider')
+    serializer_class = serializers.CircuitSerializer
     filter_class = CircuitFilter
     filter_class = CircuitFilter
 
 
-    def get_serializer_class(self):
-        if self.action == 'retrieve':
-            return serializers.CircuitDetailSerializer
-        return serializers.CircuitSerializer
-
 
 
 #
 #
 # Circuit Terminations
 # Circuit Terminations
 #
 #
 
 
-class CircuitTerminationViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
+class CircuitTerminationViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, WritableSerializerMixin,
+                                GenericViewSet):
     queryset = CircuitTermination.objects.select_related('site', 'interface__device')
     queryset = CircuitTermination.objects.select_related('site', 'interface__device')
     serializer_class = serializers.CircuitTerminationSerializer
     serializer_class = serializers.CircuitTerminationSerializer
 
 
 
 
-class NestedCircuitTerminationViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
+class NestedCircuitTerminationViewSet(CreateModelMixin, ListModelMixin ,WritableSerializerMixin, GenericViewSet):
     serializer_class = serializers.CircuitTerminationSerializer
     serializer_class = serializers.CircuitTerminationSerializer
 
 
     def get_queryset(self):
     def get_queryset(self):

+ 26 - 20
netbox/dcim/api/views.py

@@ -18,7 +18,7 @@ from dcim.models import (
 from dcim import filters
 from dcim import filters
 from extras.api.views import CustomFieldModelViewSet
 from extras.api.views import CustomFieldModelViewSet
 from extras.api.renderers import BINDZoneRenderer, FlatJSONRenderer
 from extras.api.renderers import BINDZoneRenderer, FlatJSONRenderer
-from utilities.api import ServiceUnavailable
+from utilities.api import ServiceUnavailable, WritableSerializerMixin
 from .exceptions import MissingFilterException
 from .exceptions import MissingFilterException
 from . import serializers
 from . import serializers
 
 
@@ -27,7 +27,7 @@ from . import serializers
 # Sites
 # Sites
 #
 #
 
 
-class SiteViewSet(CustomFieldModelViewSet):
+class SiteViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
     queryset = Site.objects.select_related('tenant')
     queryset = Site.objects.select_related('tenant')
     serializer_class = serializers.SiteSerializer
     serializer_class = serializers.SiteSerializer
 
 
@@ -36,7 +36,7 @@ class SiteViewSet(CustomFieldModelViewSet):
 # Rack groups
 # Rack groups
 #
 #
 
 
-class RackGroupViewSet(ModelViewSet):
+class RackGroupViewSet(WritableSerializerMixin, ModelViewSet):
     queryset = RackGroup.objects.select_related('site')
     queryset = RackGroup.objects.select_related('site')
     serializer_class = serializers.RackGroupSerializer
     serializer_class = serializers.RackGroupSerializer
     filter_class = filters.RackGroupFilter
     filter_class = filters.RackGroupFilter
@@ -55,7 +55,7 @@ class RackRoleViewSet(ModelViewSet):
 # Racks
 # Racks
 #
 #
 
 
-class RackViewSet(CustomFieldModelViewSet):
+class RackViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
     queryset = Rack.objects.select_related('site', 'group__site', 'tenant')
     queryset = Rack.objects.select_related('site', 'group__site', 'tenant')
     serializer_class = serializers.RackSerializer
     serializer_class = serializers.RackSerializer
     filter_class = filters.RackFilter
     filter_class = filters.RackFilter
@@ -102,7 +102,7 @@ class ManufacturerViewSet(ModelViewSet):
 # Device Types
 # Device Types
 #
 #
 
 
-class DeviceTypeViewSet(CustomFieldModelViewSet):
+class DeviceTypeViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
     queryset = DeviceType.objects.select_related('manufacturer')
     queryset = DeviceType.objects.select_related('manufacturer')
     serializer_class = serializers.DeviceTypeSerializer
     serializer_class = serializers.DeviceTypeSerializer
 
 
@@ -129,7 +129,7 @@ class PlatformViewSet(ModelViewSet):
 # Devices
 # Devices
 #
 #
 
 
-class DeviceViewSet(CustomFieldModelViewSet):
+class DeviceViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
     queryset = Device.objects.select_related(
     queryset = Device.objects.select_related(
         'device_type__manufacturer', 'device_role', 'tenant', 'platform', 'rack__site', 'parent_bay',
         'device_type__manufacturer', 'device_role', 'tenant', 'platform', 'rack__site', 'parent_bay',
     ).prefetch_related(
     ).prefetch_related(
@@ -144,12 +144,13 @@ class DeviceViewSet(CustomFieldModelViewSet):
 # Console Ports
 # Console Ports
 #
 #
 
 
-class ConsolePortViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
+class ConsolePortViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, WritableSerializerMixin,
+                         GenericViewSet):
     queryset = ConsolePort.objects.select_related('cs_port')
     queryset = ConsolePort.objects.select_related('cs_port')
     serializer_class = serializers.ConsolePortSerializer
     serializer_class = serializers.ConsolePortSerializer
 
 
 
 
-class ChildConsolePortViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
+class ChildConsolePortViewSet(CreateModelMixin, ListModelMixin, WritableSerializerMixin, GenericViewSet):
     serializer_class = serializers.ChildConsoleServerPortSerializer
     serializer_class = serializers.ChildConsoleServerPortSerializer
 
 
     def get_queryset(self):
     def get_queryset(self):
@@ -161,12 +162,13 @@ class ChildConsolePortViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
 # Console Server Ports
 # Console Server Ports
 #
 #
 
 
-class ConsoleServerPortViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
+class ConsoleServerPortViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, WritableSerializerMixin,
+                               GenericViewSet):
     queryset = ConsoleServerPort.objects.select_related('connected_console')
     queryset = ConsoleServerPort.objects.select_related('connected_console')
     serializer_class = serializers.ConsoleServerPortSerializer
     serializer_class = serializers.ConsoleServerPortSerializer
 
 
 
 
-class ChildConsoleServerPortViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
+class ChildConsoleServerPortViewSet(CreateModelMixin, ListModelMixin, WritableSerializerMixin, GenericViewSet):
     serializer_class = serializers.ChildConsoleServerPortSerializer
     serializer_class = serializers.ChildConsoleServerPortSerializer
 
 
     def get_queryset(self):
     def get_queryset(self):
@@ -178,12 +180,13 @@ class ChildConsoleServerPortViewSet(CreateModelMixin, ListModelMixin, GenericVie
 # Power Ports
 # Power Ports
 #
 #
 
 
-class PowerPortViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
+class PowerPortViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, WritableSerializerMixin,
+                       GenericViewSet):
     queryset = PowerPort.objects.select_related('power_outlet')
     queryset = PowerPort.objects.select_related('power_outlet')
     serializer_class = serializers.PowerPortSerializer
     serializer_class = serializers.PowerPortSerializer
 
 
 
 
-class NestedPowerPortViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
+class NestedPowerPortViewSet(CreateModelMixin, ListModelMixin, WritableSerializerMixin, GenericViewSet):
     serializer_class = serializers.ChildPowerPortSerializer
     serializer_class = serializers.ChildPowerPortSerializer
 
 
     def get_queryset(self):
     def get_queryset(self):
@@ -195,12 +198,13 @@ class NestedPowerPortViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
 # Power Outlets
 # Power Outlets
 #
 #
 
 
-class PowerOutletViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
+class PowerOutletViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, WritableSerializerMixin,
+                         GenericViewSet):
     queryset = PowerOutlet.objects.select_related('connected_port')
     queryset = PowerOutlet.objects.select_related('connected_port')
     serializer_class = serializers.PowerOutletSerializer
     serializer_class = serializers.PowerOutletSerializer
 
 
 
 
-class NestedPowerOutletViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
+class NestedPowerOutletViewSet(CreateModelMixin, ListModelMixin, WritableSerializerMixin, GenericViewSet):
     serializer_class = serializers.ChildPowerOutletSerializer
     serializer_class = serializers.ChildPowerOutletSerializer
 
 
     def get_queryset(self):
     def get_queryset(self):
@@ -212,12 +216,13 @@ class NestedPowerOutletViewSet(CreateModelMixin, ListModelMixin, GenericViewSet)
 # Interfaces
 # Interfaces
 #
 #
 
 
-class InterfaceViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
+class InterfaceViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, WritableSerializerMixin,
+                       GenericViewSet):
     queryset = Interface.objects.select_related('device')
     queryset = Interface.objects.select_related('device')
     serializer_class = serializers.InterfaceDetailSerializer
     serializer_class = serializers.InterfaceDetailSerializer
 
 
 
 
-class NestedInterfaceViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
+class NestedInterfaceViewSet(CreateModelMixin, ListModelMixin, WritableSerializerMixin, GenericViewSet):
     serializer_class = serializers.ChildInterfaceSerializer
     serializer_class = serializers.ChildInterfaceSerializer
     filter_class = filters.InterfaceFilter
     filter_class = filters.InterfaceFilter
 
 
@@ -231,12 +236,13 @@ class NestedInterfaceViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
 # Device bays
 # Device bays
 #
 #
 
 
-class DeviceBayViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
+class DeviceBayViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, WritableSerializerMixin,
+                       GenericViewSet):
     queryset = DeviceBay.objects.select_related('installed_device')
     queryset = DeviceBay.objects.select_related('installed_device')
     serializer_class = serializers.DeviceBaySerializer
     serializer_class = serializers.DeviceBaySerializer
 
 
 
 
-class NestedDeviceBayViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
+class NestedDeviceBayViewSet(CreateModelMixin, ListModelMixin, WritableSerializerMixin, GenericViewSet):
     serializer_class = serializers.ChildDeviceBaySerializer
     serializer_class = serializers.ChildDeviceBaySerializer
 
 
     def get_queryset(self):
     def get_queryset(self):
@@ -248,12 +254,12 @@ class NestedDeviceBayViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
 # Modules
 # Modules
 #
 #
 
 
-class ModuleViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
+class ModuleViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, WritableSerializerMixin, GenericViewSet):
     queryset = Module.objects.select_related('device', 'manufacturer')
     queryset = Module.objects.select_related('device', 'manufacturer')
     serializer_class = serializers.ModuleSerializer
     serializer_class = serializers.ModuleSerializer
 
 
 
 
-class NestedModuleViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
+class NestedModuleViewSet(CreateModelMixin, ListModelMixin, WritableSerializerMixin, GenericViewSet):
     serializer_class = serializers.ChildModuleSerializer
     serializer_class = serializers.ChildModuleSerializer
 
 
     def get_queryset(self):
     def get_queryset(self):

+ 2 - 1
netbox/ipam/api/serializers.py

@@ -4,6 +4,7 @@ from dcim.api.serializers import NestedDeviceSerializer, ChildInterfaceSerialize
 from extras.api.serializers import CustomFieldSerializer
 from extras.api.serializers import CustomFieldSerializer
 from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
 from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
 from tenancy.api.serializers import NestedTenantSerializer
 from tenancy.api.serializers import NestedTenantSerializer
+from utilities.api import WritableSerializerMixin
 
 
 
 
 #
 #
@@ -84,7 +85,7 @@ class NestedAggregateSerializer(serializers.HyperlinkedModelSerializer):
 # VLAN groups
 # VLAN groups
 #
 #
 
 
-class VLANGroupSerializer(serializers.ModelSerializer):
+class VLANGroupSerializer(WritableSerializerMixin, serializers.ModelSerializer):
     site = NestedSiteSerializer()
     site = NestedSiteSerializer()
 
 
     class Meta:
     class Meta:

+ 8 - 7
netbox/ipam/api/views.py

@@ -4,6 +4,7 @@ from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN,
 from ipam import filters
 from ipam import filters
 
 
 from extras.api.views import CustomFieldModelViewSet
 from extras.api.views import CustomFieldModelViewSet
+from utilities.api import WritableSerializerMixin
 from . import serializers
 from . import serializers
 
 
 
 
@@ -11,7 +12,7 @@ from . import serializers
 # VRFs
 # VRFs
 #
 #
 
 
-class VRFViewSet(CustomFieldModelViewSet):
+class VRFViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
     queryset = VRF.objects.select_related('tenant')
     queryset = VRF.objects.select_related('tenant')
     serializer_class = serializers.VRFSerializer
     serializer_class = serializers.VRFSerializer
     filter_class = filters.VRFFilter
     filter_class = filters.VRFFilter
@@ -39,7 +40,7 @@ class RIRViewSet(ModelViewSet):
 # Aggregates
 # Aggregates
 #
 #
 
 
-class AggregateViewSet(CustomFieldModelViewSet):
+class AggregateViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
     queryset = Aggregate.objects.select_related('rir')
     queryset = Aggregate.objects.select_related('rir')
     serializer_class = serializers.AggregateSerializer
     serializer_class = serializers.AggregateSerializer
     filter_class = filters.AggregateFilter
     filter_class = filters.AggregateFilter
@@ -49,7 +50,7 @@ class AggregateViewSet(CustomFieldModelViewSet):
 # Prefixes
 # Prefixes
 #
 #
 
 
-class PrefixViewSet(CustomFieldModelViewSet):
+class PrefixViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
     queryset = Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
     queryset = Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
     serializer_class = serializers.PrefixSerializer
     serializer_class = serializers.PrefixSerializer
     filter_class = filters.PrefixFilter
     filter_class = filters.PrefixFilter
@@ -59,7 +60,7 @@ class PrefixViewSet(CustomFieldModelViewSet):
 # IP addresses
 # IP addresses
 #
 #
 
 
-class IPAddressViewSet(CustomFieldModelViewSet):
+class IPAddressViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
     queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device', 'nat_inside')
     queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device', 'nat_inside')
     serializer_class = serializers.IPAddressSerializer
     serializer_class = serializers.IPAddressSerializer
     filter_class = filters.IPAddressFilter
     filter_class = filters.IPAddressFilter
@@ -69,7 +70,7 @@ class IPAddressViewSet(CustomFieldModelViewSet):
 # VLAN groups
 # VLAN groups
 #
 #
 
 
-class VLANGroupViewSet(ModelViewSet):
+class VLANGroupViewSet(WritableSerializerMixin, ModelViewSet):
     queryset = VLANGroup.objects.select_related('site')
     queryset = VLANGroup.objects.select_related('site')
     serializer_class = serializers.VLANGroupSerializer
     serializer_class = serializers.VLANGroupSerializer
     filter_class = filters.VLANGroupFilter
     filter_class = filters.VLANGroupFilter
@@ -79,7 +80,7 @@ class VLANGroupViewSet(ModelViewSet):
 # VLANs
 # VLANs
 #
 #
 
 
-class VLANViewSet(CustomFieldModelViewSet):
+class VLANViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
     queryset = VLAN.objects.select_related('site', 'group', 'tenant', 'role')
     queryset = VLAN.objects.select_related('site', 'group', 'tenant', 'role')
     serializer_class = serializers.VLANSerializer
     serializer_class = serializers.VLANSerializer
     filter_class = filters.VLANFilter
     filter_class = filters.VLANFilter
@@ -89,7 +90,7 @@ class VLANViewSet(CustomFieldModelViewSet):
 # Services
 # Services
 #
 #
 
 
-class ServiceViewSet(ModelViewSet):
+class ServiceViewSet(WritableSerializerMixin, ModelViewSet):
     queryset = Service.objects.select_related('device').prefetch_related('ipaddresses')
     queryset = Service.objects.select_related('device').prefetch_related('ipaddresses')
     serializer_class = serializers.ServiceSerializer
     serializer_class = serializers.ServiceSerializer
     filter_class = filters.ServiceFilter
     filter_class = filters.ServiceFilter

+ 2 - 1
netbox/tenancy/api/views.py

@@ -4,6 +4,7 @@ from tenancy.models import Tenant, TenantGroup
 from tenancy.filters import TenantFilter
 from tenancy.filters import TenantFilter
 
 
 from extras.api.views import CustomFieldModelViewSet
 from extras.api.views import CustomFieldModelViewSet
+from utilities.api import WritableSerializerMixin
 from . import serializers
 from . import serializers
 
 
 
 
@@ -20,7 +21,7 @@ class TenantGroupViewSet(ModelViewSet):
 # Tenants
 # Tenants
 #
 #
 
 
-class TenantViewSet(CustomFieldModelViewSet):
+class TenantViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
     queryset = Tenant.objects.select_related('group')
     queryset = Tenant.objects.select_related('group')
     serializer_class = serializers.TenantSerializer
     serializer_class = serializers.TenantSerializer
     filter_class = TenantFilter
     filter_class = TenantFilter

+ 24 - 0
netbox/utilities/api.py

@@ -1,6 +1,30 @@
 from rest_framework.exceptions import APIException
 from rest_framework.exceptions import APIException
+from rest_framework.serializers import ModelSerializer
+
+
+WRITE_OPERATIONS = ['create', 'update', 'partial_update', 'delete']
 
 
 
 
 class ServiceUnavailable(APIException):
 class ServiceUnavailable(APIException):
     status_code = 503
     status_code = 503
     default_detail = "Service temporarily unavailable, please try again later."
     default_detail = "Service temporarily unavailable, please try again later."
+
+
+class WritableSerializerMixin(object):
+    """
+    Returns a flat Serializer from the given model suitable for write operations (POST, PUT, PATCH). This is necessary
+    to allow write operations on objects which utilize nested serializers.
+    """
+
+    def get_serializer_class(self):
+
+        class WritableSerializer(ModelSerializer):
+
+            class Meta:
+                model = self.queryset.model
+                fields = '__all__'
+
+        if self.action in WRITE_OPERATIONS:
+            return WritableSerializer
+
+        return self.serializer_class