Started merging writable serializers (WIP)

This commit is contained in:
Jeremy Stretch 2018-04-04 17:01:24 -04:00
parent db3cbaf83b
commit 7241783249
10 changed files with 187 additions and 434 deletions

View File

@ -7,7 +7,7 @@ from circuits.models import Provider, Circuit, CircuitTermination, CircuitType
from dcim.api.serializers import NestedSiteSerializer, InterfaceSerializer from dcim.api.serializers import NestedSiteSerializer, InterfaceSerializer
from extras.api.customfields import CustomFieldModelSerializer from extras.api.customfields import CustomFieldModelSerializer
from tenancy.api.serializers import NestedTenantSerializer from tenancy.api.serializers import NestedTenantSerializer
from utilities.api import ChoiceFieldSerializer, ValidatedModelSerializer from utilities.api import ChoiceFieldSerializer, ValidatedModelSerializer, WritableNestedSerializer
# #
@ -24,7 +24,7 @@ class ProviderSerializer(CustomFieldModelSerializer):
] ]
class NestedProviderSerializer(serializers.ModelSerializer): class NestedProviderSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:provider-detail') url = serializers.HyperlinkedIdentityField(view_name='circuits-api:provider-detail')
class Meta: class Meta:
@ -32,16 +32,6 @@ class NestedProviderSerializer(serializers.ModelSerializer):
fields = ['id', 'url', 'name', 'slug'] fields = ['id', 'url', 'name', 'slug']
class WritableProviderSerializer(CustomFieldModelSerializer):
class Meta:
model = Provider
fields = [
'id', 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments',
'custom_fields', 'created', 'last_updated',
]
# #
# Circuit types # Circuit types
# #
@ -53,7 +43,7 @@ class CircuitTypeSerializer(ValidatedModelSerializer):
fields = ['id', 'name', 'slug'] fields = ['id', 'name', 'slug']
class NestedCircuitTypeSerializer(serializers.ModelSerializer): class NestedCircuitTypeSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittype-detail') url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittype-detail')
class Meta: class Meta:
@ -67,9 +57,9 @@ class NestedCircuitTypeSerializer(serializers.ModelSerializer):
class CircuitSerializer(CustomFieldModelSerializer): class CircuitSerializer(CustomFieldModelSerializer):
provider = NestedProviderSerializer() provider = NestedProviderSerializer()
status = ChoiceFieldSerializer(choices=CIRCUIT_STATUS_CHOICES) status = ChoiceFieldSerializer(choices=CIRCUIT_STATUS_CHOICES, required=False)
type = NestedCircuitTypeSerializer() type = NestedCircuitTypeSerializer()
tenant = NestedTenantSerializer() tenant = NestedTenantSerializer(required=False)
class Meta: class Meta:
model = Circuit model = Circuit
@ -79,7 +69,7 @@ class CircuitSerializer(CustomFieldModelSerializer):
] ]
class NestedCircuitSerializer(serializers.ModelSerializer): class NestedCircuitSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuit-detail') url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuit-detail')
class Meta: class Meta:
@ -87,33 +77,14 @@ class NestedCircuitSerializer(serializers.ModelSerializer):
fields = ['id', 'url', 'cid'] fields = ['id', 'url', 'cid']
class WritableCircuitSerializer(CustomFieldModelSerializer):
class Meta:
model = Circuit
fields = [
'id', 'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description',
'comments', 'custom_fields', 'created', 'last_updated',
]
# #
# Circuit Terminations # Circuit Terminations
# #
class CircuitTerminationSerializer(serializers.ModelSerializer): class CircuitTerminationSerializer(ValidatedModelSerializer):
circuit = NestedCircuitSerializer() circuit = NestedCircuitSerializer()
site = NestedSiteSerializer() site = NestedSiteSerializer()
interface = InterfaceSerializer() interface = InterfaceSerializer(required=False)
class Meta:
model = CircuitTermination
fields = [
'id', 'circuit', 'term_side', 'site', 'interface', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info',
]
class WritableCircuitTerminationSerializer(ValidatedModelSerializer):
class Meta: class Meta:
model = CircuitTermination model = CircuitTermination

View File

@ -30,7 +30,6 @@ class CircuitsFieldChoicesViewSet(FieldChoicesViewSet):
class ProviderViewSet(CustomFieldModelViewSet): class ProviderViewSet(CustomFieldModelViewSet):
queryset = Provider.objects.all() queryset = Provider.objects.all()
serializer_class = serializers.ProviderSerializer serializer_class = serializers.ProviderSerializer
write_serializer_class = serializers.WritableProviderSerializer
filter_class = filters.ProviderFilter filter_class = filters.ProviderFilter
@detail_route() @detail_route()
@ -61,7 +60,6 @@ class CircuitTypeViewSet(ModelViewSet):
class CircuitViewSet(CustomFieldModelViewSet): class CircuitViewSet(CustomFieldModelViewSet):
queryset = Circuit.objects.select_related('type', 'tenant', 'provider') queryset = Circuit.objects.select_related('type', 'tenant', 'provider')
serializer_class = serializers.CircuitSerializer serializer_class = serializers.CircuitSerializer
write_serializer_class = serializers.WritableCircuitSerializer
filter_class = filters.CircuitFilter filter_class = filters.CircuitFilter
@ -72,5 +70,4 @@ class CircuitViewSet(CustomFieldModelViewSet):
class CircuitTerminationViewSet(ModelViewSet): class CircuitTerminationViewSet(ModelViewSet):
queryset = CircuitTermination.objects.select_related('circuit', 'site', 'interface__device') queryset = CircuitTermination.objects.select_related('circuit', 'site', 'interface__device')
serializer_class = serializers.CircuitTerminationSerializer serializer_class = serializers.CircuitTerminationSerializer
write_serializer_class = serializers.WritableCircuitTerminationSerializer
filter_class = filters.CircuitTerminationFilter filter_class = filters.CircuitTerminationFilter

View File

@ -20,7 +20,7 @@ from extras.api.customfields import CustomFieldModelSerializer
from ipam.models import IPAddress, VLAN from ipam.models import IPAddress, VLAN
from tenancy.api.serializers import NestedTenantSerializer from tenancy.api.serializers import NestedTenantSerializer
from users.api.serializers import NestedUserSerializer from users.api.serializers import NestedUserSerializer
from utilities.api import ChoiceFieldSerializer, TimeZoneField, ValidatedModelSerializer from utilities.api import ChoiceFieldSerializer, TimeZoneField, ValidatedModelSerializer, WritableNestedSerializer
from virtualization.models import Cluster from virtualization.models import Cluster
@ -28,7 +28,7 @@ from virtualization.models import Cluster
# Regions # Regions
# #
class NestedRegionSerializer(serializers.ModelSerializer): class NestedRegionSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:region-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:region-detail')
class Meta: class Meta:
@ -37,14 +37,7 @@ class NestedRegionSerializer(serializers.ModelSerializer):
class RegionSerializer(serializers.ModelSerializer): class RegionSerializer(serializers.ModelSerializer):
parent = NestedRegionSerializer() parent = NestedRegionSerializer(required=False)
class Meta:
model = Region
fields = ['id', 'name', 'slug', 'parent']
class WritableRegionSerializer(ValidatedModelSerializer):
class Meta: class Meta:
model = Region model = Region
@ -56,9 +49,9 @@ class WritableRegionSerializer(ValidatedModelSerializer):
# #
class SiteSerializer(CustomFieldModelSerializer): class SiteSerializer(CustomFieldModelSerializer):
status = ChoiceFieldSerializer(choices=SITE_STATUS_CHOICES) status = ChoiceFieldSerializer(choices=SITE_STATUS_CHOICES, required=False)
region = NestedRegionSerializer() region = NestedRegionSerializer(required=False)
tenant = NestedTenantSerializer() tenant = NestedTenantSerializer(required=False)
time_zone = TimeZoneField(required=False) time_zone = TimeZoneField(required=False)
class Meta: class Meta:
@ -71,7 +64,7 @@ class SiteSerializer(CustomFieldModelSerializer):
] ]
class NestedSiteSerializer(serializers.ModelSerializer): class NestedSiteSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:site-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:site-detail')
class Meta: class Meta:
@ -79,23 +72,11 @@ class NestedSiteSerializer(serializers.ModelSerializer):
fields = ['id', 'url', 'name', 'slug'] fields = ['id', 'url', 'name', 'slug']
class WritableSiteSerializer(CustomFieldModelSerializer):
time_zone = TimeZoneField(required=False)
class Meta:
model = Site
fields = [
'id', 'name', 'slug', 'status', 'region', 'tenant', 'facility', 'asn', 'time_zone', 'description',
'physical_address', 'shipping_address', 'contact_name', 'contact_phone', 'contact_email', 'comments',
'custom_fields', 'created', 'last_updated',
]
# #
# Rack groups # Rack groups
# #
class RackGroupSerializer(serializers.ModelSerializer): class RackGroupSerializer(ValidatedModelSerializer):
site = NestedSiteSerializer() site = NestedSiteSerializer()
class Meta: class Meta:
@ -103,7 +84,7 @@ class RackGroupSerializer(serializers.ModelSerializer):
fields = ['id', 'name', 'slug', 'site'] fields = ['id', 'name', 'slug', 'site']
class NestedRackGroupSerializer(serializers.ModelSerializer): class NestedRackGroupSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackgroup-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackgroup-detail')
class Meta: class Meta:
@ -111,13 +92,6 @@ class NestedRackGroupSerializer(serializers.ModelSerializer):
fields = ['id', 'url', 'name', 'slug'] fields = ['id', 'url', 'name', 'slug']
class WritableRackGroupSerializer(ValidatedModelSerializer):
class Meta:
model = RackGroup
fields = ['id', 'name', 'slug', 'site']
# #
# Rack roles # Rack roles
# #
@ -129,7 +103,7 @@ class RackRoleSerializer(ValidatedModelSerializer):
fields = ['id', 'name', 'slug', 'color'] fields = ['id', 'name', 'slug', 'color']
class NestedRackRoleSerializer(serializers.ModelSerializer): class NestedRackRoleSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackrole-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackrole-detail')
class Meta: class Meta:
@ -143,11 +117,11 @@ class NestedRackRoleSerializer(serializers.ModelSerializer):
class RackSerializer(CustomFieldModelSerializer): class RackSerializer(CustomFieldModelSerializer):
site = NestedSiteSerializer() site = NestedSiteSerializer()
group = NestedRackGroupSerializer() group = NestedRackGroupSerializer(required=False)
tenant = NestedTenantSerializer() tenant = NestedTenantSerializer(required=False)
role = NestedRackRoleSerializer() role = NestedRackRoleSerializer(required=False)
type = ChoiceFieldSerializer(choices=RACK_TYPE_CHOICES) type = ChoiceFieldSerializer(choices=RACK_TYPE_CHOICES, required=False)
width = ChoiceFieldSerializer(choices=RACK_WIDTH_CHOICES) width = ChoiceFieldSerializer(choices=RACK_WIDTH_CHOICES, required=False)
class Meta: class Meta:
model = Rack model = Rack
@ -155,24 +129,6 @@ class RackSerializer(CustomFieldModelSerializer):
'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'role', 'serial', 'type', 'width', 'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'role', 'serial', 'type', 'width',
'u_height', 'desc_units', 'comments', 'custom_fields', 'created', 'last_updated', 'u_height', 'desc_units', 'comments', 'custom_fields', 'created', 'last_updated',
] ]
class NestedRackSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rack-detail')
class Meta:
model = Rack
fields = ['id', 'url', 'name', 'display_name']
class WritableRackSerializer(CustomFieldModelSerializer):
class Meta:
model = Rack
fields = [
'id', 'name', 'facility_id', 'site', 'group', 'tenant', 'role', 'serial', 'type', 'width', 'u_height',
'desc_units', 'comments', 'custom_fields', 'created', 'last_updated',
]
# Omit the UniqueTogetherValidator that would be automatically added to validate (site, facility_id). This # Omit the UniqueTogetherValidator that would be automatically added to validate (site, facility_id). This
# prevents facility_id from being interpreted as a required field. # prevents facility_id from being interpreted as a required field.
validators = [ validators = [
@ -188,16 +144,24 @@ class WritableRackSerializer(CustomFieldModelSerializer):
validator(data) validator(data)
# Enforce model validation # Enforce model validation
super(WritableRackSerializer, self).validate(data) super(RackSerializer, self).validate(data)
return data return data
class NestedRackSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rack-detail')
class Meta:
model = Rack
fields = ['id', 'url', 'name', 'display_name']
# #
# Rack units # Rack units
# #
class NestedDeviceSerializer(serializers.ModelSerializer): class NestedDeviceSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:device-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:device-detail')
class Meta: class Meta:
@ -219,23 +183,16 @@ class RackUnitSerializer(serializers.Serializer):
# Rack reservations # Rack reservations
# #
class RackReservationSerializer(serializers.ModelSerializer): class RackReservationSerializer(ValidatedModelSerializer):
rack = NestedRackSerializer() rack = NestedRackSerializer()
user = NestedUserSerializer() user = NestedUserSerializer()
tenant = NestedTenantSerializer() tenant = NestedTenantSerializer(required=False)
class Meta: class Meta:
model = RackReservation model = RackReservation
fields = ['id', 'rack', 'units', 'created', 'user', 'tenant', 'description'] fields = ['id', 'rack', 'units', 'created', 'user', 'tenant', 'description']
class WritableRackReservationSerializer(ValidatedModelSerializer):
class Meta:
model = RackReservation
fields = ['id', 'rack', 'units', 'user', 'description']
# #
# Manufacturers # Manufacturers
# #
@ -247,7 +204,7 @@ class ManufacturerSerializer(ValidatedModelSerializer):
fields = ['id', 'name', 'slug'] fields = ['id', 'name', 'slug']
class NestedManufacturerSerializer(serializers.ModelSerializer): class NestedManufacturerSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:manufacturer-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:manufacturer-detail')
class Meta: class Meta:
@ -261,8 +218,8 @@ class NestedManufacturerSerializer(serializers.ModelSerializer):
class DeviceTypeSerializer(CustomFieldModelSerializer): class DeviceTypeSerializer(CustomFieldModelSerializer):
manufacturer = NestedManufacturerSerializer() manufacturer = NestedManufacturerSerializer()
interface_ordering = ChoiceFieldSerializer(choices=IFACE_ORDERING_CHOICES) interface_ordering = ChoiceFieldSerializer(choices=IFACE_ORDERING_CHOICES, required=False)
subdevice_role = ChoiceFieldSerializer(choices=SUBDEVICE_ROLE_CHOICES) subdevice_role = ChoiceFieldSerializer(choices=SUBDEVICE_ROLE_CHOICES, required=False)
instance_count = serializers.IntegerField(source='instances.count', read_only=True) instance_count = serializers.IntegerField(source='instances.count', read_only=True)
class Meta: class Meta:
@ -274,30 +231,20 @@ class DeviceTypeSerializer(CustomFieldModelSerializer):
] ]
class NestedDeviceTypeSerializer(serializers.ModelSerializer): class NestedDeviceTypeSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicetype-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicetype-detail')
manufacturer = NestedManufacturerSerializer() manufacturer = NestedManufacturerSerializer(read_only=True)
class Meta: class Meta:
model = DeviceType model = DeviceType
fields = ['id', 'url', 'manufacturer', 'model', 'slug'] fields = ['id', 'url', 'manufacturer', 'model', 'slug']
class WritableDeviceTypeSerializer(CustomFieldModelSerializer):
class Meta:
model = DeviceType
fields = [
'id', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'interface_ordering',
'is_console_server', 'is_pdu', 'is_network_device', 'subdevice_role', 'comments', 'custom_fields',
]
# #
# Console port templates # Console port templates
# #
class ConsolePortTemplateSerializer(serializers.ModelSerializer): class ConsolePortTemplateSerializer(ValidatedModelSerializer):
device_type = NestedDeviceTypeSerializer() device_type = NestedDeviceTypeSerializer()
class Meta: class Meta:
@ -305,18 +252,11 @@ class ConsolePortTemplateSerializer(serializers.ModelSerializer):
fields = ['id', 'device_type', 'name'] fields = ['id', 'device_type', 'name']
class WritableConsolePortTemplateSerializer(ValidatedModelSerializer):
class Meta:
model = ConsolePortTemplate
fields = ['id', 'device_type', 'name']
# #
# Console server port templates # Console server port templates
# #
class ConsoleServerPortTemplateSerializer(serializers.ModelSerializer): class ConsoleServerPortTemplateSerializer(ValidatedModelSerializer):
device_type = NestedDeviceTypeSerializer() device_type = NestedDeviceTypeSerializer()
class Meta: class Meta:
@ -324,18 +264,11 @@ class ConsoleServerPortTemplateSerializer(serializers.ModelSerializer):
fields = ['id', 'device_type', 'name'] fields = ['id', 'device_type', 'name']
class WritableConsoleServerPortTemplateSerializer(ValidatedModelSerializer):
class Meta:
model = ConsoleServerPortTemplate
fields = ['id', 'device_type', 'name']
# #
# Power port templates # Power port templates
# #
class PowerPortTemplateSerializer(serializers.ModelSerializer): class PowerPortTemplateSerializer(ValidatedModelSerializer):
device_type = NestedDeviceTypeSerializer() device_type = NestedDeviceTypeSerializer()
class Meta: class Meta:
@ -343,18 +276,11 @@ class PowerPortTemplateSerializer(serializers.ModelSerializer):
fields = ['id', 'device_type', 'name'] fields = ['id', 'device_type', 'name']
class WritablePowerPortTemplateSerializer(ValidatedModelSerializer):
class Meta:
model = PowerPortTemplate
fields = ['id', 'device_type', 'name']
# #
# Power outlet templates # Power outlet templates
# #
class PowerOutletTemplateSerializer(serializers.ModelSerializer): class PowerOutletTemplateSerializer(ValidatedModelSerializer):
device_type = NestedDeviceTypeSerializer() device_type = NestedDeviceTypeSerializer()
class Meta: class Meta:
@ -362,27 +288,13 @@ class PowerOutletTemplateSerializer(serializers.ModelSerializer):
fields = ['id', 'device_type', 'name'] fields = ['id', 'device_type', 'name']
class WritablePowerOutletTemplateSerializer(ValidatedModelSerializer):
class Meta:
model = PowerOutletTemplate
fields = ['id', 'device_type', 'name']
# #
# Interface templates # Interface templates
# #
class InterfaceTemplateSerializer(serializers.ModelSerializer): class InterfaceTemplateSerializer(ValidatedModelSerializer):
device_type = NestedDeviceTypeSerializer() device_type = NestedDeviceTypeSerializer()
form_factor = ChoiceFieldSerializer(choices=IFACE_FF_CHOICES) form_factor = ChoiceFieldSerializer(choices=IFACE_FF_CHOICES, required=False)
class Meta:
model = InterfaceTemplate
fields = ['id', 'device_type', 'name', 'form_factor', 'mgmt_only']
class WritableInterfaceTemplateSerializer(ValidatedModelSerializer):
class Meta: class Meta:
model = InterfaceTemplate model = InterfaceTemplate
@ -393,7 +305,7 @@ class WritableInterfaceTemplateSerializer(ValidatedModelSerializer):
# Device bay templates # Device bay templates
# #
class DeviceBayTemplateSerializer(serializers.ModelSerializer): class DeviceBayTemplateSerializer(ValidatedModelSerializer):
device_type = NestedDeviceTypeSerializer() device_type = NestedDeviceTypeSerializer()
class Meta: class Meta:
@ -401,13 +313,6 @@ class DeviceBayTemplateSerializer(serializers.ModelSerializer):
fields = ['id', 'device_type', 'name'] fields = ['id', 'device_type', 'name']
class WritableDeviceBayTemplateSerializer(ValidatedModelSerializer):
class Meta:
model = DeviceBayTemplate
fields = ['id', 'device_type', 'name']
# #
# Device roles # Device roles
# #
@ -419,7 +324,7 @@ class DeviceRoleSerializer(ValidatedModelSerializer):
fields = ['id', 'name', 'slug', 'color', 'vm_role'] fields = ['id', 'name', 'slug', 'color', 'vm_role']
class NestedDeviceRoleSerializer(serializers.ModelSerializer): class NestedDeviceRoleSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicerole-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicerole-detail')
class Meta: class Meta:
@ -431,15 +336,15 @@ class NestedDeviceRoleSerializer(serializers.ModelSerializer):
# Platforms # Platforms
# #
class PlatformSerializer(serializers.ModelSerializer): class PlatformSerializer(ValidatedModelSerializer):
manufacturer = NestedManufacturerSerializer() manufacturer = NestedManufacturerSerializer(required=False)
class Meta: class Meta:
model = Platform model = Platform
fields = ['id', 'name', 'slug', 'manufacturer', 'napalm_driver', 'rpc_client'] fields = ['id', 'name', 'slug', 'manufacturer', 'napalm_driver', 'rpc_client']
class NestedPlatformSerializer(serializers.ModelSerializer): class NestedPlatformSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:platform-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:platform-detail')
class Meta: class Meta:
@ -447,13 +352,6 @@ class NestedPlatformSerializer(serializers.ModelSerializer):
fields = ['id', 'url', 'name', 'slug'] fields = ['id', 'url', 'name', 'slug']
class WritablePlatformSerializer(ValidatedModelSerializer):
class Meta:
model = Platform
fields = ['id', 'name', 'slug', 'manufacturer', 'napalm_driver', 'rpc_client']
# #
# Devices # Devices
# #
@ -489,18 +387,18 @@ class DeviceVirtualChassisSerializer(serializers.ModelSerializer):
class DeviceSerializer(CustomFieldModelSerializer): class DeviceSerializer(CustomFieldModelSerializer):
device_type = NestedDeviceTypeSerializer() device_type = NestedDeviceTypeSerializer()
device_role = NestedDeviceRoleSerializer() device_role = NestedDeviceRoleSerializer()
tenant = NestedTenantSerializer() tenant = NestedTenantSerializer(required=False)
platform = NestedPlatformSerializer() platform = NestedPlatformSerializer(required=False)
site = NestedSiteSerializer() site = NestedSiteSerializer()
rack = NestedRackSerializer() rack = NestedRackSerializer(required=False)
face = ChoiceFieldSerializer(choices=RACK_FACE_CHOICES) face = ChoiceFieldSerializer(choices=RACK_FACE_CHOICES, required=False)
status = ChoiceFieldSerializer(choices=DEVICE_STATUS_CHOICES) status = ChoiceFieldSerializer(choices=DEVICE_STATUS_CHOICES, required=False)
primary_ip = DeviceIPAddressSerializer() primary_ip = DeviceIPAddressSerializer(read_only=True)
primary_ip4 = DeviceIPAddressSerializer() primary_ip4 = DeviceIPAddressSerializer(required=False)
primary_ip6 = DeviceIPAddressSerializer() primary_ip6 = DeviceIPAddressSerializer(required=False)
parent_device = serializers.SerializerMethodField() parent_device = serializers.SerializerMethodField()
cluster = NestedClusterSerializer() cluster = NestedClusterSerializer(required=False)
virtual_chassis = DeviceVirtualChassisSerializer() virtual_chassis = DeviceVirtualChassisSerializer(required=False)
class Meta: class Meta:
model = Device model = Device
@ -510,27 +408,6 @@ class DeviceSerializer(CustomFieldModelSerializer):
'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'custom_fields', 'created', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'custom_fields', 'created',
'last_updated', 'last_updated',
] ]
def get_parent_device(self, obj):
try:
device_bay = obj.parent_bay
except DeviceBay.DoesNotExist:
return None
context = {'request': self.context['request']}
data = NestedDeviceSerializer(instance=device_bay.device, context=context).data
data['device_bay'] = NestedDeviceBaySerializer(instance=device_bay, context=context).data
return data
class WritableDeviceSerializer(CustomFieldModelSerializer):
class Meta:
model = Device
fields = [
'id', 'name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag', 'site', 'rack',
'position', 'face', 'status', 'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position',
'vc_priority', 'comments', 'custom_fields', 'created', 'last_updated',
]
validators = [] validators = []
def validate(self, data): def validate(self, data):
@ -542,16 +419,26 @@ class WritableDeviceSerializer(CustomFieldModelSerializer):
validator(data) validator(data)
# Enforce model validation # Enforce model validation
super(WritableDeviceSerializer, self).validate(data) super(DeviceSerializer, self).validate(data)
return data return data
def get_parent_device(self, obj):
try:
device_bay = obj.parent_bay
except DeviceBay.DoesNotExist:
return None
context = {'request': self.context['request']}
data = NestedDeviceSerializer(instance=device_bay.device, context=context).data
data['device_bay'] = NestedDeviceBaySerializer(instance=device_bay, context=context).data
return data
# #
# Console server ports # Console server ports
# #
class ConsoleServerPortSerializer(serializers.ModelSerializer): class ConsoleServerPortSerializer(ValidatedModelSerializer):
device = NestedDeviceSerializer() device = NestedDeviceSerializer()
class Meta: class Meta:
@ -560,27 +447,22 @@ class ConsoleServerPortSerializer(serializers.ModelSerializer):
read_only_fields = ['connected_console'] read_only_fields = ['connected_console']
class WritableConsoleServerPortSerializer(ValidatedModelSerializer): class NestedConsoleServerPortSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverport-detail')
device = NestedDeviceSerializer(read_only=True)
class Meta: class Meta:
model = ConsoleServerPort model = ConsoleServerPort
fields = ['id', 'device', 'name'] fields = ['id', 'url', 'device', 'name']
# #
# Console ports # Console ports
# #
class ConsolePortSerializer(serializers.ModelSerializer): class ConsolePortSerializer(ValidatedModelSerializer):
device = NestedDeviceSerializer() device = NestedDeviceSerializer()
cs_port = ConsoleServerPortSerializer() cs_port = NestedConsoleServerPortSerializer(required=False)
class Meta:
model = ConsolePort
fields = ['id', 'device', 'name', 'cs_port', 'connection_status']
class WritableConsolePortSerializer(ValidatedModelSerializer):
class Meta: class Meta:
model = ConsolePort model = ConsolePort
@ -591,7 +473,7 @@ class WritableConsolePortSerializer(ValidatedModelSerializer):
# Power outlets # Power outlets
# #
class PowerOutletSerializer(serializers.ModelSerializer): class PowerOutletSerializer(ValidatedModelSerializer):
device = NestedDeviceSerializer() device = NestedDeviceSerializer()
class Meta: class Meta:
@ -600,27 +482,22 @@ class PowerOutletSerializer(serializers.ModelSerializer):
read_only_fields = ['connected_port'] read_only_fields = ['connected_port']
class WritablePowerOutletSerializer(ValidatedModelSerializer): class NestedPowerOutletSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlet-detail')
device = NestedDeviceSerializer(read_only=True)
class Meta: class Meta:
model = PowerOutlet model = PowerOutlet
fields = ['id', 'device', 'name'] fields = ['id', 'url', 'device', 'name']
# #
# Power ports # Power ports
# #
class PowerPortSerializer(serializers.ModelSerializer): class PowerPortSerializer(ValidatedModelSerializer):
device = NestedDeviceSerializer() device = NestedDeviceSerializer()
power_outlet = PowerOutletSerializer() power_outlet = NestedPowerOutletSerializer(required=False)
class Meta:
model = PowerPort
fields = ['id', 'device', 'name', 'power_outlet', 'connection_status']
class WritablePowerPortSerializer(ValidatedModelSerializer):
class Meta: class Meta:
model = PowerPort model = PowerPort
@ -631,12 +508,13 @@ class WritablePowerPortSerializer(ValidatedModelSerializer):
# Interfaces # Interfaces
# #
class NestedInterfaceSerializer(serializers.ModelSerializer): class NestedInterfaceSerializer(WritableNestedSerializer):
device = NestedDeviceSerializer(read_only=True)
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
class Meta: class Meta:
model = Interface model = Interface
fields = ['id', 'url', 'name'] fields = ['id', 'url', 'device', 'name']
class InterfaceNestedCircuitSerializer(serializers.ModelSerializer): class InterfaceNestedCircuitSerializer(serializers.ModelSerializer):
@ -647,8 +525,8 @@ class InterfaceNestedCircuitSerializer(serializers.ModelSerializer):
fields = ['id', 'url', 'cid'] fields = ['id', 'url', 'cid']
class InterfaceCircuitTerminationSerializer(serializers.ModelSerializer): class InterfaceCircuitTerminationSerializer(WritableNestedSerializer):
circuit = InterfaceNestedCircuitSerializer() circuit = InterfaceNestedCircuitSerializer(read_only=True)
class Meta: class Meta:
model = CircuitTermination model = CircuitTermination
@ -658,7 +536,7 @@ class InterfaceCircuitTerminationSerializer(serializers.ModelSerializer):
# Cannot import ipam.api.NestedVLANSerializer due to circular dependency # Cannot import ipam.api.NestedVLANSerializer due to circular dependency
class InterfaceVLANSerializer(serializers.ModelSerializer): class InterfaceVLANSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlan-detail') url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlan-detail')
class Meta: class Meta:
@ -666,16 +544,16 @@ class InterfaceVLANSerializer(serializers.ModelSerializer):
fields = ['id', 'url', 'vid', 'name', 'display_name'] fields = ['id', 'url', 'vid', 'name', 'display_name']
class InterfaceSerializer(serializers.ModelSerializer): class InterfaceSerializer(ValidatedModelSerializer):
device = NestedDeviceSerializer() device = NestedDeviceSerializer()
form_factor = ChoiceFieldSerializer(choices=IFACE_FF_CHOICES) form_factor = ChoiceFieldSerializer(choices=IFACE_FF_CHOICES, required=False)
lag = NestedInterfaceSerializer() lag = NestedInterfaceSerializer(required=False)
is_connected = serializers.SerializerMethodField(read_only=True) is_connected = serializers.SerializerMethodField(read_only=True)
interface_connection = serializers.SerializerMethodField(read_only=True) interface_connection = serializers.SerializerMethodField(read_only=True)
circuit_termination = InterfaceCircuitTerminationSerializer() circuit_termination = InterfaceCircuitTerminationSerializer(required=False)
untagged_vlan = InterfaceVLANSerializer() untagged_vlan = InterfaceVLANSerializer(required=False)
mode = ChoiceFieldSerializer(choices=IFACE_MODE_CHOICES) mode = ChoiceFieldSerializer(choices=IFACE_MODE_CHOICES, required=False)
tagged_vlans = InterfaceVLANSerializer(many=True) tagged_vlans = InterfaceVLANSerializer(many=True, required=False)
class Meta: class Meta:
model = Interface model = Interface
@ -684,51 +562,6 @@ class InterfaceSerializer(serializers.ModelSerializer):
'is_connected', 'interface_connection', 'circuit_termination', 'mode', 'untagged_vlan', 'tagged_vlans', 'is_connected', 'interface_connection', 'circuit_termination', 'mode', 'untagged_vlan', 'tagged_vlans',
] ]
def get_is_connected(self, obj):
"""
Return True if the interface has a connected interface or circuit termination.
"""
if obj.connection:
return True
try:
circuit_termination = obj.circuit_termination
return True
except CircuitTermination.DoesNotExist:
pass
return False
def get_interface_connection(self, obj):
if obj.connection:
return OrderedDict((
('interface', PeerInterfaceSerializer(obj.connected_interface, context=self.context).data),
('status', obj.connection.connection_status),
))
return None
class PeerInterfaceSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
device = NestedDeviceSerializer()
form_factor = ChoiceFieldSerializer(choices=IFACE_FF_CHOICES)
lag = NestedInterfaceSerializer()
class Meta:
model = Interface
fields = [
'id', 'url', 'device', 'name', 'form_factor', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only',
'description',
]
class WritableInterfaceSerializer(ValidatedModelSerializer):
class Meta:
model = Interface
fields = [
'id', 'device', 'name', 'form_factor', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only', 'description',
'mode', 'untagged_vlan', 'tagged_vlans',
]
def validate(self, data): def validate(self, data):
# All associated VLANs be global or assigned to the parent device's site. # All associated VLANs be global or assigned to the parent device's site.
@ -746,23 +579,58 @@ class WritableInterfaceSerializer(ValidatedModelSerializer):
"be global.".format(vlan) "be global.".format(vlan)
}) })
return super(WritableInterfaceSerializer, self).validate(data) return super(InterfaceSerializer, self).validate(data)
def get_is_connected(self, obj):
"""
Return True if the interface has a connected interface or circuit termination.
"""
if obj.connection:
return True
try:
circuit_termination = obj.circuit_termination
return True
except CircuitTermination.DoesNotExist:
pass
return False
def get_interface_connection(self, obj):
if obj.connection:
return OrderedDict((
('interface', NestedInterfaceSerializer(obj.connected_interface, context=self.context).data),
('status', obj.connection.connection_status),
))
return None
# class PeerInterfaceSerializer(serializers.ModelSerializer):
# url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
# device = NestedDeviceSerializer()
# form_factor = ChoiceFieldSerializer(choices=IFACE_FF_CHOICES)
# lag = NestedInterfaceSerializer()
#
# class Meta:
# model = Interface
# fields = [
# 'id', 'url', 'device', 'name', 'form_factor', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only',
# 'description',
# ]
# #
# Device bays # Device bays
# #
class DeviceBaySerializer(serializers.ModelSerializer): class DeviceBaySerializer(ValidatedModelSerializer):
device = NestedDeviceSerializer() device = NestedDeviceSerializer()
installed_device = NestedDeviceSerializer() installed_device = NestedDeviceSerializer(required=False)
class Meta: class Meta:
model = DeviceBay model = DeviceBay
fields = ['id', 'device', 'name', 'installed_device'] fields = ['id', 'device', 'name', 'installed_device']
class NestedDeviceBaySerializer(serializers.ModelSerializer): class NestedDeviceBaySerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicebay-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicebay-detail')
class Meta: class Meta:
@ -770,32 +638,15 @@ class NestedDeviceBaySerializer(serializers.ModelSerializer):
fields = ['id', 'url', 'name'] fields = ['id', 'url', 'name']
class WritableDeviceBaySerializer(ValidatedModelSerializer):
class Meta:
model = DeviceBay
fields = ['id', 'device', 'name', 'installed_device']
# #
# Inventory items # Inventory items
# #
class InventoryItemSerializer(serializers.ModelSerializer): class InventoryItemSerializer(ValidatedModelSerializer):
device = NestedDeviceSerializer() device = NestedDeviceSerializer()
manufacturer = NestedManufacturerSerializer()
class Meta:
model = InventoryItem
fields = [
'id', 'device', 'parent', 'name', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'discovered',
'description',
]
class WritableInventoryItemSerializer(ValidatedModelSerializer):
# Provide a default value to satisfy UniqueTogetherValidator # Provide a default value to satisfy UniqueTogetherValidator
parent = serializers.PrimaryKeyRelatedField(queryset=InventoryItem.objects.all(), allow_null=True, default=None) parent = serializers.PrimaryKeyRelatedField(queryset=InventoryItem.objects.all(), allow_null=True, default=None)
manufacturer = NestedManufacturerSerializer()
class Meta: class Meta:
model = InventoryItem model = InventoryItem
@ -809,17 +660,17 @@ class WritableInventoryItemSerializer(ValidatedModelSerializer):
# Interface connections # Interface connections
# #
class InterfaceConnectionSerializer(serializers.ModelSerializer): class InterfaceConnectionSerializer(ValidatedModelSerializer):
interface_a = PeerInterfaceSerializer() interface_a = NestedInterfaceSerializer()
interface_b = PeerInterfaceSerializer() interface_b = NestedInterfaceSerializer()
connection_status = ChoiceFieldSerializer(choices=CONNECTION_STATUS_CHOICES) connection_status = ChoiceFieldSerializer(choices=CONNECTION_STATUS_CHOICES, required=False)
class Meta: class Meta:
model = InterfaceConnection model = InterfaceConnection
fields = ['id', 'interface_a', 'interface_b', 'connection_status'] fields = ['id', 'interface_a', 'interface_b', 'connection_status']
class NestedInterfaceConnectionSerializer(serializers.ModelSerializer): class NestedInterfaceConnectionSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interfaceconnection-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interfaceconnection-detail')
class Meta: class Meta:
@ -827,18 +678,11 @@ class NestedInterfaceConnectionSerializer(serializers.ModelSerializer):
fields = ['id', 'url', 'connection_status'] fields = ['id', 'url', 'connection_status']
class WritableInterfaceConnectionSerializer(ValidatedModelSerializer):
class Meta:
model = InterfaceConnection
fields = ['id', 'interface_a', 'interface_b', 'connection_status']
# #
# Virtual chassis # Virtual chassis
# #
class VirtualChassisSerializer(serializers.ModelSerializer): class VirtualChassisSerializer(ValidatedModelSerializer):
master = NestedDeviceSerializer() master = NestedDeviceSerializer()
class Meta: class Meta:
@ -846,16 +690,9 @@ class VirtualChassisSerializer(serializers.ModelSerializer):
fields = ['id', 'master', 'domain'] fields = ['id', 'master', 'domain']
class NestedVirtualChassisSerializer(serializers.ModelSerializer): class NestedVirtualChassisSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail')
class Meta: class Meta:
model = VirtualChassis model = VirtualChassis
fields = ['id', 'url'] fields = ['id', 'url']
class WritableVirtualChassisSerializer(ValidatedModelSerializer):
class Meta:
model = VirtualChassis
fields = ['id', 'master', 'domain']

View File

@ -52,7 +52,6 @@ class DCIMFieldChoicesViewSet(FieldChoicesViewSet):
class RegionViewSet(ModelViewSet): class RegionViewSet(ModelViewSet):
queryset = Region.objects.all() queryset = Region.objects.all()
serializer_class = serializers.RegionSerializer serializer_class = serializers.RegionSerializer
write_serializer_class = serializers.WritableRegionSerializer
filter_class = filters.RegionFilter filter_class = filters.RegionFilter
@ -63,7 +62,6 @@ class RegionViewSet(ModelViewSet):
class SiteViewSet(CustomFieldModelViewSet): class SiteViewSet(CustomFieldModelViewSet):
queryset = Site.objects.select_related('region', 'tenant') queryset = Site.objects.select_related('region', 'tenant')
serializer_class = serializers.SiteSerializer serializer_class = serializers.SiteSerializer
write_serializer_class = serializers.WritableSiteSerializer
filter_class = filters.SiteFilter filter_class = filters.SiteFilter
@detail_route() @detail_route()
@ -84,7 +82,6 @@ class SiteViewSet(CustomFieldModelViewSet):
class RackGroupViewSet(ModelViewSet): class RackGroupViewSet(ModelViewSet):
queryset = RackGroup.objects.select_related('site') queryset = RackGroup.objects.select_related('site')
serializer_class = serializers.RackGroupSerializer serializer_class = serializers.RackGroupSerializer
write_serializer_class = serializers.WritableRackGroupSerializer
filter_class = filters.RackGroupFilter filter_class = filters.RackGroupFilter
@ -105,7 +102,6 @@ class RackRoleViewSet(ModelViewSet):
class RackViewSet(CustomFieldModelViewSet): class RackViewSet(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
write_serializer_class = serializers.WritableRackSerializer
filter_class = filters.RackFilter filter_class = filters.RackFilter
@detail_route() @detail_route()
@ -136,7 +132,6 @@ class RackViewSet(CustomFieldModelViewSet):
class RackReservationViewSet(ModelViewSet): class RackReservationViewSet(ModelViewSet):
queryset = RackReservation.objects.select_related('rack', 'user', 'tenant') queryset = RackReservation.objects.select_related('rack', 'user', 'tenant')
serializer_class = serializers.RackReservationSerializer serializer_class = serializers.RackReservationSerializer
write_serializer_class = serializers.WritableRackReservationSerializer
filter_class = filters.RackReservationFilter filter_class = filters.RackReservationFilter
# Assign user from request # Assign user from request
@ -161,7 +156,6 @@ class ManufacturerViewSet(ModelViewSet):
class DeviceTypeViewSet(CustomFieldModelViewSet): class DeviceTypeViewSet(CustomFieldModelViewSet):
queryset = DeviceType.objects.select_related('manufacturer') queryset = DeviceType.objects.select_related('manufacturer')
serializer_class = serializers.DeviceTypeSerializer serializer_class = serializers.DeviceTypeSerializer
write_serializer_class = serializers.WritableDeviceTypeSerializer
filter_class = filters.DeviceTypeFilter filter_class = filters.DeviceTypeFilter
@ -172,42 +166,36 @@ class DeviceTypeViewSet(CustomFieldModelViewSet):
class ConsolePortTemplateViewSet(ModelViewSet): class ConsolePortTemplateViewSet(ModelViewSet):
queryset = ConsolePortTemplate.objects.select_related('device_type__manufacturer') queryset = ConsolePortTemplate.objects.select_related('device_type__manufacturer')
serializer_class = serializers.ConsolePortTemplateSerializer serializer_class = serializers.ConsolePortTemplateSerializer
write_serializer_class = serializers.WritableConsolePortTemplateSerializer
filter_class = filters.ConsolePortTemplateFilter filter_class = filters.ConsolePortTemplateFilter
class ConsoleServerPortTemplateViewSet(ModelViewSet): class ConsoleServerPortTemplateViewSet(ModelViewSet):
queryset = ConsoleServerPortTemplate.objects.select_related('device_type__manufacturer') queryset = ConsoleServerPortTemplate.objects.select_related('device_type__manufacturer')
serializer_class = serializers.ConsoleServerPortTemplateSerializer serializer_class = serializers.ConsoleServerPortTemplateSerializer
write_serializer_class = serializers.WritableConsoleServerPortTemplateSerializer
filter_class = filters.ConsoleServerPortTemplateFilter filter_class = filters.ConsoleServerPortTemplateFilter
class PowerPortTemplateViewSet(ModelViewSet): class PowerPortTemplateViewSet(ModelViewSet):
queryset = PowerPortTemplate.objects.select_related('device_type__manufacturer') queryset = PowerPortTemplate.objects.select_related('device_type__manufacturer')
serializer_class = serializers.PowerPortTemplateSerializer serializer_class = serializers.PowerPortTemplateSerializer
write_serializer_class = serializers.WritablePowerPortTemplateSerializer
filter_class = filters.PowerPortTemplateFilter filter_class = filters.PowerPortTemplateFilter
class PowerOutletTemplateViewSet(ModelViewSet): class PowerOutletTemplateViewSet(ModelViewSet):
queryset = PowerOutletTemplate.objects.select_related('device_type__manufacturer') queryset = PowerOutletTemplate.objects.select_related('device_type__manufacturer')
serializer_class = serializers.PowerOutletTemplateSerializer serializer_class = serializers.PowerOutletTemplateSerializer
write_serializer_class = serializers.WritablePowerOutletTemplateSerializer
filter_class = filters.PowerOutletTemplateFilter filter_class = filters.PowerOutletTemplateFilter
class InterfaceTemplateViewSet(ModelViewSet): class InterfaceTemplateViewSet(ModelViewSet):
queryset = InterfaceTemplate.objects.select_related('device_type__manufacturer') queryset = InterfaceTemplate.objects.select_related('device_type__manufacturer')
serializer_class = serializers.InterfaceTemplateSerializer serializer_class = serializers.InterfaceTemplateSerializer
write_serializer_class = serializers.WritableInterfaceTemplateSerializer
filter_class = filters.InterfaceTemplateFilter filter_class = filters.InterfaceTemplateFilter
class DeviceBayTemplateViewSet(ModelViewSet): class DeviceBayTemplateViewSet(ModelViewSet):
queryset = DeviceBayTemplate.objects.select_related('device_type__manufacturer') queryset = DeviceBayTemplate.objects.select_related('device_type__manufacturer')
serializer_class = serializers.DeviceBayTemplateSerializer serializer_class = serializers.DeviceBayTemplateSerializer
write_serializer_class = serializers.WritableDeviceBayTemplateSerializer
filter_class = filters.DeviceBayTemplateFilter filter_class = filters.DeviceBayTemplateFilter
@ -228,7 +216,6 @@ class DeviceRoleViewSet(ModelViewSet):
class PlatformViewSet(ModelViewSet): class PlatformViewSet(ModelViewSet):
queryset = Platform.objects.all() queryset = Platform.objects.all()
serializer_class = serializers.PlatformSerializer serializer_class = serializers.PlatformSerializer
write_serializer_class = serializers.WritablePlatformSerializer
filter_class = filters.PlatformFilter filter_class = filters.PlatformFilter
@ -244,7 +231,6 @@ class DeviceViewSet(CustomFieldModelViewSet):
'primary_ip4__nat_outside', 'primary_ip6__nat_outside', 'primary_ip4__nat_outside', 'primary_ip6__nat_outside',
) )
serializer_class = serializers.DeviceSerializer serializer_class = serializers.DeviceSerializer
write_serializer_class = serializers.WritableDeviceSerializer
filter_class = filters.DeviceFilter filter_class = filters.DeviceFilter
@detail_route(url_path='napalm') @detail_route(url_path='napalm')
@ -318,35 +304,30 @@ class DeviceViewSet(CustomFieldModelViewSet):
class ConsolePortViewSet(ModelViewSet): class ConsolePortViewSet(ModelViewSet):
queryset = ConsolePort.objects.select_related('device', 'cs_port__device') queryset = ConsolePort.objects.select_related('device', 'cs_port__device')
serializer_class = serializers.ConsolePortSerializer serializer_class = serializers.ConsolePortSerializer
write_serializer_class = serializers.WritableConsolePortSerializer
filter_class = filters.ConsolePortFilter filter_class = filters.ConsolePortFilter
class ConsoleServerPortViewSet(ModelViewSet): class ConsoleServerPortViewSet(ModelViewSet):
queryset = ConsoleServerPort.objects.select_related('device', 'connected_console__device') queryset = ConsoleServerPort.objects.select_related('device', 'connected_console__device')
serializer_class = serializers.ConsoleServerPortSerializer serializer_class = serializers.ConsoleServerPortSerializer
write_serializer_class = serializers.WritableConsoleServerPortSerializer
filter_class = filters.ConsoleServerPortFilter filter_class = filters.ConsoleServerPortFilter
class PowerPortViewSet(ModelViewSet): class PowerPortViewSet(ModelViewSet):
queryset = PowerPort.objects.select_related('device', 'power_outlet__device') queryset = PowerPort.objects.select_related('device', 'power_outlet__device')
serializer_class = serializers.PowerPortSerializer serializer_class = serializers.PowerPortSerializer
write_serializer_class = serializers.WritablePowerPortSerializer
filter_class = filters.PowerPortFilter filter_class = filters.PowerPortFilter
class PowerOutletViewSet(ModelViewSet): class PowerOutletViewSet(ModelViewSet):
queryset = PowerOutlet.objects.select_related('device', 'connected_port__device') queryset = PowerOutlet.objects.select_related('device', 'connected_port__device')
serializer_class = serializers.PowerOutletSerializer serializer_class = serializers.PowerOutletSerializer
write_serializer_class = serializers.WritablePowerOutletSerializer
filter_class = filters.PowerOutletFilter filter_class = filters.PowerOutletFilter
class InterfaceViewSet(ModelViewSet): class InterfaceViewSet(ModelViewSet):
queryset = Interface.objects.select_related('device') queryset = Interface.objects.select_related('device')
serializer_class = serializers.InterfaceSerializer serializer_class = serializers.InterfaceSerializer
write_serializer_class = serializers.WritableInterfaceSerializer
filter_class = filters.InterfaceFilter filter_class = filters.InterfaceFilter
@detail_route() @detail_route()
@ -363,14 +344,12 @@ class InterfaceViewSet(ModelViewSet):
class DeviceBayViewSet(ModelViewSet): class DeviceBayViewSet(ModelViewSet):
queryset = DeviceBay.objects.select_related('installed_device') queryset = DeviceBay.objects.select_related('installed_device')
serializer_class = serializers.DeviceBaySerializer serializer_class = serializers.DeviceBaySerializer
write_serializer_class = serializers.WritableDeviceBaySerializer
filter_class = filters.DeviceBayFilter filter_class = filters.DeviceBayFilter
class InventoryItemViewSet(ModelViewSet): class InventoryItemViewSet(ModelViewSet):
queryset = InventoryItem.objects.select_related('device', 'manufacturer') queryset = InventoryItem.objects.select_related('device', 'manufacturer')
serializer_class = serializers.InventoryItemSerializer serializer_class = serializers.InventoryItemSerializer
write_serializer_class = serializers.WritableInventoryItemSerializer
filter_class = filters.InventoryItemFilter filter_class = filters.InventoryItemFilter
@ -393,7 +372,6 @@ class PowerConnectionViewSet(ListModelMixin, GenericViewSet):
class InterfaceConnectionViewSet(ModelViewSet): class InterfaceConnectionViewSet(ModelViewSet):
queryset = InterfaceConnection.objects.select_related('interface_a__device', 'interface_b__device') queryset = InterfaceConnection.objects.select_related('interface_a__device', 'interface_b__device')
serializer_class = serializers.InterfaceConnectionSerializer serializer_class = serializers.InterfaceConnectionSerializer
write_serializer_class = serializers.WritableInterfaceConnectionSerializer
filter_class = filters.InterfaceConnectionFilter filter_class = filters.InterfaceConnectionFilter
@ -404,7 +382,6 @@ class InterfaceConnectionViewSet(ModelViewSet):
class VirtualChassisViewSet(ModelViewSet): class VirtualChassisViewSet(ModelViewSet):
queryset = VirtualChassis.objects.all() queryset = VirtualChassis.objects.all()
serializer_class = serializers.VirtualChassisSerializer serializer_class = serializers.VirtualChassisSerializer
write_serializer_class = serializers.WritableVirtualChassisSerializer
# #

View File

@ -1,6 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.test.utils import override_settings
from django.urls import reverse from django.urls import reverse
from rest_framework import status from rest_framework import status
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
@ -2321,6 +2322,7 @@ class InterfaceTest(HttpStatusMixin, APITestCase):
self.assertEqual(interface4.device_id, data['device']) self.assertEqual(interface4.device_id, data['device'])
self.assertEqual(interface4.name, data['name']) self.assertEqual(interface4.name, data['name'])
@override_settings(DEBUG=True)
def test_create_interface_with_802_1q(self): def test_create_interface_with_802_1q(self):
data = { data = {
@ -2368,6 +2370,7 @@ class InterfaceTest(HttpStatusMixin, APITestCase):
self.assertEqual(response.data[1]['name'], data[1]['name']) self.assertEqual(response.data[1]['name'], data[1]['name'])
self.assertEqual(response.data[2]['name'], data[2]['name']) self.assertEqual(response.data[2]['name'], data[2]['name'])
@override_settings(DEBUG=True)
def test_create_interface_802_1q_bulk(self): def test_create_interface_802_1q_bulk(self):
data = [ data = [
@ -2852,9 +2855,9 @@ class InterfaceConnectionTest(HttpStatusMixin, APITestCase):
self.assertHttpStatus(response, status.HTTP_201_CREATED) self.assertHttpStatus(response, status.HTTP_201_CREATED)
self.assertEqual(InterfaceConnection.objects.count(), 6) self.assertEqual(InterfaceConnection.objects.count(), 6)
self.assertEqual(response.data[0]['interface_a'], data[0]['interface_a']) for i in range(0, 3):
self.assertEqual(response.data[1]['interface_a'], data[1]['interface_a']) self.assertEqual(response.data[i]['interface_a']['id'], data[i]['interface_a'])
self.assertEqual(response.data[2]['interface_a'], data[2]['interface_a']) self.assertEqual(response.data[i]['interface_b']['id'], data[i]['interface_b'])
def test_update_interfaceconnection(self): def test_update_interfaceconnection(self):
@ -3052,12 +3055,9 @@ class VirtualChassisTest(HttpStatusMixin, APITestCase):
response = self.client.post(url, data, format='json', **self.header) response = self.client.post(url, data, format='json', **self.header)
self.assertHttpStatus(response, status.HTTP_201_CREATED) self.assertHttpStatus(response, status.HTTP_201_CREATED)
self.assertEqual(VirtualChassis.objects.count(), 5) self.assertEqual(VirtualChassis.objects.count(), 5)
self.assertEqual(response.data[0]['master'], data[0]['master']) for i in range(0, 3):
self.assertEqual(response.data[0]['domain'], data[0]['domain']) self.assertEqual(response.data[i]['master']['id'], data[i]['master'])
self.assertEqual(response.data[1]['master'], data[1]['master']) self.assertEqual(response.data[i]['domain'], data[i]['domain'])
self.assertEqual(response.data[1]['domain'], data[1]['domain'])
self.assertEqual(response.data[2]['master'], data[2]['master'])
self.assertEqual(response.data[2]['domain'], data[2]['domain'])
def test_update_virtualchassis(self): def test_update_virtualchassis(self):

View File

@ -15,7 +15,7 @@ from utilities.api import ChoiceFieldSerializer, ContentTypeFieldSerializer, Val
# Graphs # Graphs
# #
class GraphSerializer(serializers.ModelSerializer): class GraphSerializer(ValidatedModelSerializer):
type = ChoiceFieldSerializer(choices=GRAPH_TYPE_CHOICES) type = ChoiceFieldSerializer(choices=GRAPH_TYPE_CHOICES)
class Meta: class Meta:
@ -23,13 +23,6 @@ class GraphSerializer(serializers.ModelSerializer):
fields = ['id', 'type', 'weight', 'name', 'source', 'link'] fields = ['id', 'type', 'weight', 'name', 'source', 'link']
class WritableGraphSerializer(serializers.ModelSerializer):
class Meta:
model = Graph
fields = ['id', 'type', 'weight', 'name', 'source', 'link']
class RenderedGraphSerializer(serializers.ModelSerializer): class RenderedGraphSerializer(serializers.ModelSerializer):
embed_url = serializers.SerializerMethodField() embed_url = serializers.SerializerMethodField()
embed_link = serializers.SerializerMethodField() embed_link = serializers.SerializerMethodField()
@ -50,7 +43,7 @@ class RenderedGraphSerializer(serializers.ModelSerializer):
# Export templates # Export templates
# #
class ExportTemplateSerializer(serializers.ModelSerializer): class ExportTemplateSerializer(ValidatedModelSerializer):
class Meta: class Meta:
model = ExportTemplate model = ExportTemplate
@ -61,7 +54,7 @@ class ExportTemplateSerializer(serializers.ModelSerializer):
# Topology maps # Topology maps
# #
class TopologyMapSerializer(serializers.ModelSerializer): class TopologyMapSerializer(ValidatedModelSerializer):
site = NestedSiteSerializer() site = NestedSiteSerializer()
class Meta: class Meta:
@ -69,23 +62,34 @@ class TopologyMapSerializer(serializers.ModelSerializer):
fields = ['id', 'name', 'slug', 'site', 'device_patterns', 'description'] fields = ['id', 'name', 'slug', 'site', 'device_patterns', 'description']
class WritableTopologyMapSerializer(serializers.ModelSerializer):
class Meta:
model = TopologyMap
fields = ['id', 'name', 'slug', 'site', 'device_patterns', 'description']
# #
# Image attachments # Image attachments
# #
class ImageAttachmentSerializer(serializers.ModelSerializer): class ImageAttachmentSerializer(ValidatedModelSerializer):
parent = serializers.SerializerMethodField() content_type = ContentTypeFieldSerializer()
parent = serializers.SerializerMethodField(read_only=True)
class Meta: class Meta:
model = ImageAttachment model = ImageAttachment
fields = ['id', 'parent', 'name', 'image', 'image_height', 'image_width', 'created'] fields = [
'id', 'content_type', 'object_id', 'parent', 'name', 'image', 'image_height', 'image_width', 'created',
]
def validate(self, data):
# Validate that the parent object exists
try:
data['content_type'].get_object_for_this_type(id=data['object_id'])
except ObjectDoesNotExist:
raise serializers.ValidationError(
"Invalid parent object: {} ID {}".format(data['content_type'], data['object_id'])
)
# Enforce model validation
super(ImageAttachmentSerializer, self).validate(data)
return data
def get_parent(self, obj): def get_parent(self, obj):
@ -102,29 +106,6 @@ class ImageAttachmentSerializer(serializers.ModelSerializer):
return serializer(obj.parent, context={'request': self.context['request']}).data return serializer(obj.parent, context={'request': self.context['request']}).data
class WritableImageAttachmentSerializer(ValidatedModelSerializer):
content_type = ContentTypeFieldSerializer()
class Meta:
model = ImageAttachment
fields = ['id', 'content_type', 'object_id', 'name', 'image']
def validate(self, data):
# Validate that the parent object exists
try:
data['content_type'].get_object_for_this_type(id=data['object_id'])
except ObjectDoesNotExist:
raise serializers.ValidationError(
"Invalid parent object: {} ID {}".format(data['content_type'], data['object_id'])
)
# Enforce model validation
super(WritableImageAttachmentSerializer, self).validate(data)
return data
# #
# Reports # Reports
# #

View File

@ -67,7 +67,6 @@ class CustomFieldModelViewSet(ModelViewSet):
class GraphViewSet(ModelViewSet): class GraphViewSet(ModelViewSet):
queryset = Graph.objects.all() queryset = Graph.objects.all()
serializer_class = serializers.GraphSerializer serializer_class = serializers.GraphSerializer
write_serializer_class = serializers.WritableGraphSerializer
filter_class = filters.GraphFilter filter_class = filters.GraphFilter
@ -88,7 +87,6 @@ class ExportTemplateViewSet(ModelViewSet):
class TopologyMapViewSet(ModelViewSet): class TopologyMapViewSet(ModelViewSet):
queryset = TopologyMap.objects.select_related('site') queryset = TopologyMap.objects.select_related('site')
serializer_class = serializers.TopologyMapSerializer serializer_class = serializers.TopologyMapSerializer
write_serializer_class = serializers.WritableTopologyMapSerializer
filter_class = filters.TopologyMapFilter filter_class = filters.TopologyMapFilter
@detail_route() @detail_route()
@ -118,7 +116,6 @@ class TopologyMapViewSet(ModelViewSet):
class ImageAttachmentViewSet(ModelViewSet): class ImageAttachmentViewSet(ModelViewSet):
queryset = ImageAttachment.objects.all() queryset = ImageAttachment.objects.all()
serializer_class = serializers.ImageAttachmentSerializer serializer_class = serializers.ImageAttachmentSerializer
write_serializer_class = serializers.WritableImageAttachmentSerializer
# #

View File

@ -4,7 +4,7 @@ from rest_framework import serializers
from extras.api.customfields import CustomFieldModelSerializer from extras.api.customfields import CustomFieldModelSerializer
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from utilities.api import ValidatedModelSerializer from utilities.api import ValidatedModelSerializer, WritableNestedSerializer
# #
@ -18,7 +18,7 @@ class TenantGroupSerializer(ValidatedModelSerializer):
fields = ['id', 'name', 'slug'] fields = ['id', 'name', 'slug']
class NestedTenantGroupSerializer(serializers.ModelSerializer): class NestedTenantGroupSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenantgroup-detail') url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenantgroup-detail')
class Meta: class Meta:
@ -31,23 +31,16 @@ class NestedTenantGroupSerializer(serializers.ModelSerializer):
# #
class TenantSerializer(CustomFieldModelSerializer): class TenantSerializer(CustomFieldModelSerializer):
group = NestedTenantGroupSerializer() group = NestedTenantGroupSerializer(required=False)
class Meta: class Meta:
model = Tenant model = Tenant
fields = ['id', 'name', 'slug', 'group', 'description', 'comments', 'custom_fields', 'created', 'last_updated'] fields = ['id', 'name', 'slug', 'group', 'description', 'comments', 'custom_fields', 'created', 'last_updated']
class NestedTenantSerializer(serializers.ModelSerializer): class NestedTenantSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenant-detail') url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenant-detail')
class Meta: class Meta:
model = Tenant model = Tenant
fields = ['id', 'url', 'name', 'slug'] fields = ['id', 'url', 'name', 'slug']
class WritableTenantSerializer(CustomFieldModelSerializer):
class Meta:
model = Tenant
fields = ['id', 'name', 'slug', 'group', 'description', 'comments', 'custom_fields', 'created', 'last_updated']

View File

@ -32,5 +32,4 @@ class TenantGroupViewSet(ModelViewSet):
class TenantViewSet(CustomFieldModelViewSet): class TenantViewSet(CustomFieldModelViewSet):
queryset = Tenant.objects.select_related('group') queryset = Tenant.objects.select_related('group')
serializer_class = serializers.TenantSerializer serializer_class = serializers.TenantSerializer
write_serializer_class = serializers.WritableTenantSerializer
filter_class = filters.TenantFilter filter_class = filters.TenantFilter

View File

@ -1,10 +1,11 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.contrib.auth.models import User from django.contrib.auth.models import User
from rest_framework import serializers
from utilities.api import WritableNestedSerializer
class NestedUserSerializer(serializers.ModelSerializer): class NestedUserSerializer(WritableNestedSerializer):
class Meta: class Meta:
model = User model = User