class CustomFieldSerializer(ValidatedModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="extras-api:customfield-detail") content_types = ContentTypeField( queryset=ContentType.objects.filter( FeatureQuery("custom_fields").get_query()), many=True, ) type = ChoiceField(choices=CustomFieldTypeChoices) filter_logic = ChoiceField(choices=CustomFieldFilterLogicChoices, required=False) class Meta: model = CustomField fields = [ "id", "url", "content_types", "type", "name", "label", "description", "required", "filter_logic", "default", "weight", "validation_minimum", "validation_maximum", "validation_regex", ]
class PowerOutletTemplateSerializer(CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="dcim-api:poweroutlettemplate-detail") device_type = NestedDeviceTypeSerializer() type = ChoiceField(choices=PowerOutletTypeChoices, allow_blank=True, required=False) power_port = NestedPowerPortTemplateSerializer(required=False) feed_leg = ChoiceField(choices=PowerOutletFeedLegChoices, allow_blank=True, required=False) class Meta: model = PowerOutletTemplate fields = [ "id", "url", "device_type", "name", "label", "type", "power_port", "feed_leg", "description", "custom_fields", "computed_fields", ] opt_in_fields = ["computed_fields"]
class PowerOutletSerializer( TaggedObjectSerializer, CableTerminationSerializer, ConnectedEndpointSerializer, CustomFieldModelSerializer, ): url = serializers.HyperlinkedIdentityField(view_name="dcim-api:poweroutlet-detail") device = NestedDeviceSerializer() type = ChoiceField(choices=PowerOutletTypeChoices, allow_blank=True, required=False) power_port = NestedPowerPortSerializer(required=False) feed_leg = ChoiceField(choices=PowerOutletFeedLegChoices, allow_blank=True, required=False) cable = NestedCableSerializer(read_only=True) class Meta: model = PowerOutlet fields = [ "id", "url", "device", "name", "label", "type", "power_port", "feed_leg", "description", "cable", "cable_peer", "cable_peer_type", "connected_endpoint", "connected_endpoint_type", "connected_endpoint_reachable", "tags", "custom_fields", ]
class RackSerializer(TaggedObjectSerializer, StatusModelSerializerMixin, CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField(view_name="dcim-api:rack-detail") site = NestedSiteSerializer() group = NestedRackGroupSerializer(required=False, allow_null=True, default=None) tenant = NestedTenantSerializer(required=False, allow_null=True) role = NestedRackRoleSerializer(required=False, allow_null=True) type = ChoiceField(choices=RackTypeChoices, allow_blank=True, required=False) width = ChoiceField(choices=RackWidthChoices, required=False) outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False) device_count = serializers.IntegerField(read_only=True) powerfeed_count = serializers.IntegerField(read_only=True) class Meta: model = Rack fields = [ "id", "url", "name", "facility_id", "display_name", "site", "group", "tenant", "status", "role", "serial", "asset_tag", "type", "width", "u_height", "desc_units", "outer_width", "outer_depth", "outer_unit", "comments", "tags", "custom_fields", "created", "last_updated", "device_count", "powerfeed_count", ] # Omit the UniqueTogetherValidator that would be automatically added to validate (group, facility_id). This # prevents facility_id from being interpreted as a required field. validators = [UniqueTogetherValidator(queryset=Rack.objects.all(), fields=("group", "name"))] def validate(self, data): # Validate uniqueness of (group, facility_id) since we omitted the automatically-created validator from Meta. if data.get("facility_id", None): validator = UniqueTogetherValidator(queryset=Rack.objects.all(), fields=("group", "facility_id")) validator(data, self) # Enforce model validation super().validate(data) return data
class IPAddressSerializer(TaggedObjectSerializer, StatusModelSerializerMixin, CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="ipam-api:ipaddress-detail") family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True) address = IPFieldSerializer() vrf = NestedVRFSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True) role = ChoiceField(choices=IPAddressRoleChoices, allow_blank=True, required=False) assigned_object_type = ContentTypeField( queryset=ContentType.objects.filter( constants.IPADDRESS_ASSIGNMENT_MODELS), required=False, allow_null=True, ) assigned_object = serializers.SerializerMethodField(read_only=True) nat_inside = NestedIPAddressSerializer(required=False, allow_null=True) nat_outside = NestedIPAddressSerializer(read_only=True) class Meta: model = IPAddress fields = [ "id", "url", "family", "address", "vrf", "tenant", "status", "role", "assigned_object_type", "assigned_object_id", "assigned_object", "nat_inside", "nat_outside", "dns_name", "description", "tags", "custom_fields", "created", "last_updated", "computed_fields", ] read_only_fields = ["family"] opt_in_fields = ["computed_fields"] @swagger_serializer_method(serializer_or_field=serializers.DictField) def get_assigned_object(self, obj): if obj.assigned_object is None: return None serializer = get_serializer_for_model(obj.assigned_object, prefix="Nested") context = {"request": self.context["request"]} return serializer(obj.assigned_object, context=context).data
class PowerFeedSerializer( TaggedObjectSerializer, CableTerminationSerializer, ConnectedEndpointSerializer, StatusModelSerializerMixin, CustomFieldModelSerializer, ): url = serializers.HyperlinkedIdentityField( view_name="dcim-api:powerfeed-detail") power_panel = NestedPowerPanelSerializer() rack = NestedRackSerializer(required=False, allow_null=True, default=None) type = ChoiceField(choices=PowerFeedTypeChoices, default=PowerFeedTypeChoices.TYPE_PRIMARY) supply = ChoiceField(choices=PowerFeedSupplyChoices, default=PowerFeedSupplyChoices.SUPPLY_AC) phase = ChoiceField(choices=PowerFeedPhaseChoices, default=PowerFeedPhaseChoices.PHASE_SINGLE) cable = NestedCableSerializer(read_only=True) class Meta: model = PowerFeed fields = [ "id", "url", "power_panel", "rack", "name", "status", "type", "supply", "phase", "voltage", "amperage", "max_utilization", "comments", "cable", "cable_peer", "cable_peer_type", "connected_endpoint", "connected_endpoint_type", "connected_endpoint_reachable", "tags", "custom_fields", "created", "last_updated", "computed_fields", ] opt_in_fields = ["computed_fields"]
class JobResultSerializer(serializers.ModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="extras-api:jobresult-detail") user = NestedUserSerializer(read_only=True) status = ChoiceField(choices=JobResultStatusChoices, read_only=True) job_model = NestedJobSerializer(read_only=True) obj_type = ContentTypeField(read_only=True) schedule = NestedScheduledJobSerializer(read_only=True) class Meta: model = JobResult fields = [ "id", "url", "created", "completed", "name", "job_model", "obj_type", "status", "user", "data", "job_id", "schedule", ]
class PrefixSerializer(TaggedObjectSerializer, StatusModelSerializerMixin, CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="ipam-api:prefix-detail") family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True) prefix = IPFieldSerializer() site = NestedSiteSerializer(required=False, allow_null=True) vrf = NestedVRFSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True) vlan = NestedVLANSerializer(required=False, allow_null=True) role = NestedRoleSerializer(required=False, allow_null=True) class Meta: model = Prefix fields = [ "id", "url", "family", "prefix", "site", "vrf", "tenant", "vlan", "status", "role", "is_pool", "description", "tags", "custom_fields", "created", "last_updated", "computed_fields", ] read_only_fields = ["family"] opt_in_fields = ["computed_fields"]
class ServiceSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="ipam-api:service-detail") device = NestedDeviceSerializer(required=False, allow_null=True) virtual_machine = NestedVirtualMachineSerializer(required=False, allow_null=True) protocol = ChoiceField(choices=ServiceProtocolChoices, required=False) ipaddresses = SerializedPKRelatedField( queryset=IPAddress.objects.all(), serializer=NestedIPAddressSerializer, required=False, many=True, ) ports = serializers.ListField(child=serializers.IntegerField( min_value=constants.SERVICE_PORT_MIN, max_value=constants.SERVICE_PORT_MAX, )) class Meta: model = Service fields = [ "id", "url", "device", "virtual_machine", "name", "ports", "protocol", "ipaddresses", "description", "tags", "custom_fields", "created", "last_updated", ]
class ConsolePortSerializer( TaggedObjectSerializer, CableTerminationSerializer, ConnectedEndpointSerializer, CustomFieldModelSerializer, ): url = serializers.HyperlinkedIdentityField( view_name="dcim-api:consoleport-detail") device = NestedDeviceSerializer() type = ChoiceField(choices=ConsolePortTypeChoices, allow_blank=True, required=False) cable = NestedCableSerializer(read_only=True) class Meta: model = ConsolePort fields = [ "id", "url", "device", "name", "label", "type", "description", "cable", "cable_peer", "cable_peer_type", "connected_endpoint", "connected_endpoint_type", "connected_endpoint_reachable", "tags", "custom_fields", "computed_fields", ] opt_in_fields = ["computed_fields"]
class DeviceTypeSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="dcim-api:devicetype-detail") manufacturer = NestedManufacturerSerializer() subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False) device_count = serializers.IntegerField(read_only=True) class Meta: model = DeviceType fields = [ "id", "url", "manufacturer", "model", "slug", "part_number", "u_height", "is_full_depth", "subdevice_role", "front_image", "rear_image", "comments", "tags", "custom_fields", "created", "last_updated", "device_count", "computed_fields", ] opt_in_fields = ["computed_fields"]
class AggregateSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="ipam-api:aggregate-detail") family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True) prefix = IPFieldSerializer() rir = NestedRIRSerializer() tenant = NestedTenantSerializer(required=False, allow_null=True) class Meta: model = Aggregate fields = [ "id", "url", "family", "prefix", "rir", "tenant", "date_added", "description", "tags", "custom_fields", "created", "last_updated", "computed_fields", ] read_only_fields = ["family"] opt_in_fields = ["computed_fields"]
class FrontPortSerializer(TaggedObjectSerializer, CableTerminationSerializer, CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="dcim-api:frontport-detail") device = NestedDeviceSerializer() type = ChoiceField(choices=PortTypeChoices) rear_port = FrontPortRearPortSerializer() cable = NestedCableSerializer(read_only=True) class Meta: model = FrontPort fields = [ "id", "url", "device", "name", "label", "type", "rear_port", "rear_port_position", "description", "cable", "cable_peer", "cable_peer_type", "tags", "custom_fields", "computed_fields", ] opt_in_fields = ["computed_fields"]
class CableSerializer(TaggedObjectSerializer, StatusModelSerializerMixin, CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="dcim-api:cable-detail") termination_a_type = ContentTypeField( queryset=ContentType.objects.filter(CABLE_TERMINATION_MODELS)) termination_b_type = ContentTypeField( queryset=ContentType.objects.filter(CABLE_TERMINATION_MODELS)) termination_a = serializers.SerializerMethodField(read_only=True) termination_b = serializers.SerializerMethodField(read_only=True) length_unit = ChoiceField(choices=CableLengthUnitChoices, allow_blank=True, required=False) class Meta: model = Cable fields = [ "id", "url", "termination_a_type", "termination_a_id", "termination_a", "termination_b_type", "termination_b_id", "termination_b", "type", "status", "label", "color", "length", "length_unit", "tags", "custom_fields", "computed_fields", ] opt_in_fields = ["computed_fields"] 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 @swagger_serializer_method(serializer_or_field=serializers.DictField) def get_termination_a(self, obj): return self._get_termination(obj, "a") @swagger_serializer_method(serializer_or_field=serializers.DictField) def get_termination_b(self, obj): return self._get_termination(obj, "b")
class NestedJobResultSerializer(serializers.ModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="extras-api:jobresult-detail") status = ChoiceField(choices=choices.JobResultStatusChoices) user = NestedUserSerializer(read_only=True) class Meta: model = models.JobResult fields = ["url", "created", "completed", "user", "status"]
class RackUnitSerializer(serializers.Serializer): """ A rack unit is an abstraction formed by the set (rack, position, face); it does not exist as a row in the database. """ id = serializers.IntegerField(read_only=True) name = serializers.CharField(read_only=True) face = ChoiceField(choices=DeviceFaceChoices, read_only=True) device = NestedDeviceSerializer(read_only=True) occupied = serializers.BooleanField(read_only=True)
class DeviceTypeSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="dcim-api:devicetype-detail") manufacturer = NestedManufacturerSerializer() subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False) device_count = serializers.IntegerField(read_only=True) class Meta: model = DeviceType fields = [ "id", "url", "manufacturer", "model", "slug", "part_number", "u_height", "is_full_depth", "subdevice_role", "front_image", "rear_image", "comments", "tags", "custom_fields", "created", "last_updated", "device_count", "computed_fields", ] opt_in_fields = ["computed_fields"] # Omit the UniqueTogetherValidator that would be automatically added to validate (manufacturer, slug). This # prevents slug from being interpreted as a required field. # TODO: Remove if/when slug is globally unique. This would be a breaking change. validators = [ UniqueTogetherValidator(queryset=DeviceType.objects.all(), fields=("manufacturer", "model")) ] def validate(self, data): # Validate uniqueness of (manufacturer, slug) since we omitted the automatically-created validator from Meta. # TODO: Remove if/when slug is globally unique. This would be a breaking change. if data.get("slug", None): validator = UniqueTogetherValidator( queryset=DeviceType.objects.all(), fields=("manufacturer", "slug")) validator(data, self) # Enforce model validation super().validate(data) return data
class ConsoleServerPortTemplateSerializer(CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField(view_name="dcim-api:consoleserverporttemplate-detail") device_type = NestedDeviceTypeSerializer() type = ChoiceField(choices=ConsolePortTypeChoices, allow_blank=True, required=False) class Meta: model = ConsoleServerPortTemplate fields = [ "id", "url", "device_type", "name", "label", "type", "description", "custom_fields", ]
class VMInterfaceSerializer(TaggedObjectSerializer, ValidatedModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="virtualization-api:vminterface-detail") virtual_machine = NestedVirtualMachineSerializer() mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False) untagged_vlan = NestedVLANSerializer(required=False, allow_null=True) tagged_vlans = SerializedPKRelatedField( queryset=VLAN.objects.all(), serializer=NestedVLANSerializer, required=False, many=True, ) class Meta: model = VMInterface fields = [ "id", "url", "virtual_machine", "name", "enabled", "mtu", "mac_address", "description", "mode", "untagged_vlan", "tagged_vlans", "tags", ] def validate(self, data): # Validate many-to-many VLAN assignments virtual_machine = self.instance.virtual_machine if self.instance else data.get( "virtual_machine") for vlan in data.get("tagged_vlans", []): if vlan.site not in [virtual_machine.site, None]: raise serializers.ValidationError({ "tagged_vlans": f"VLAN {vlan} must belong to the same site as the interface's parent virtual " f"machine, or it must be global." }) return super().validate(data)
class InterfaceTemplateSerializer(CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField(view_name="dcim-api:interfacetemplate-detail") device_type = NestedDeviceTypeSerializer() type = ChoiceField(choices=InterfaceTypeChoices) class Meta: model = InterfaceTemplate fields = [ "id", "url", "device_type", "name", "label", "type", "mgmt_only", "description", "custom_fields", ]
class RearPortTemplateSerializer(CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField(view_name="dcim-api:rearporttemplate-detail") device_type = NestedDeviceTypeSerializer() type = ChoiceField(choices=PortTypeChoices) class Meta: model = RearPortTemplate fields = [ "id", "url", "device_type", "name", "label", "type", "positions", "description", "custom_fields", ]
class ObjectChangeSerializer(serializers.ModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="extras-api:objectchange-detail") user = NestedUserSerializer(read_only=True) action = ChoiceField(choices=ObjectChangeActionChoices, read_only=True) changed_object_type = ContentTypeField(read_only=True) changed_object = serializers.SerializerMethodField(read_only=True) class Meta: model = ObjectChange fields = [ "id", "url", "time", "user", "user_name", "request_id", "action", "changed_object_type", "changed_object_id", "changed_object", "object_data", ] @swagger_serializer_method(serializer_or_field=serializers.DictField) def get_changed_object(self, obj): """ Serialize a nested representation of the changed object. """ if obj.changed_object is None: return None try: serializer = get_serializer_for_model(obj.changed_object, prefix="Nested") except SerializerNotFound: return obj.object_repr context = {"request": self.context["request"]} data = serializer(obj.changed_object, context=context).data return data
class PowerPortTemplateSerializer(CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField(view_name="dcim-api:powerporttemplate-detail") device_type = NestedDeviceTypeSerializer() type = ChoiceField(choices=PowerPortTypeChoices, allow_blank=True, required=False) class Meta: model = PowerPortTemplate fields = [ "id", "url", "device_type", "name", "label", "type", "maximum_draw", "allocated_draw", "description", "custom_fields", "computed_fields", ] opt_in_fields = ["computed_fields"]
class FrontPortTemplateSerializer(CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField(view_name="dcim-api:frontporttemplate-detail") device_type = NestedDeviceTypeSerializer() type = ChoiceField(choices=PortTypeChoices) rear_port = NestedRearPortTemplateSerializer() class Meta: model = FrontPortTemplate fields = [ "id", "url", "device_type", "name", "label", "type", "rear_port", "rear_port_position", "description", "custom_fields", "computed_fields", ] opt_in_fields = ["computed_fields"]
class InterfaceSerializer( TaggedObjectSerializer, CableTerminationSerializer, ConnectedEndpointSerializer, CustomFieldModelSerializer, ): url = serializers.HyperlinkedIdentityField( view_name="dcim-api:interface-detail") device = NestedDeviceSerializer() type = ChoiceField(choices=InterfaceTypeChoices) lag = NestedInterfaceSerializer(required=False, allow_null=True) mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False) untagged_vlan = NestedVLANSerializer(required=False, allow_null=True) tagged_vlans = SerializedPKRelatedField( queryset=VLAN.objects.all(), serializer=NestedVLANSerializer, required=False, many=True, ) cable = NestedCableSerializer(read_only=True) count_ipaddresses = serializers.IntegerField(read_only=True) class Meta: model = Interface fields = [ "id", "url", "device", "name", "label", "type", "enabled", "lag", "mtu", "mac_address", "mgmt_only", "description", "mode", "untagged_vlan", "tagged_vlans", "cable", "cable_peer", "cable_peer_type", "connected_endpoint", "connected_endpoint_type", "connected_endpoint_reachable", "tags", "count_ipaddresses", "custom_fields", "computed_fields", ] opt_in_fields = ["computed_fields"] def validate(self, data): # Validate many-to-many VLAN assignments device = self.instance.device if self.instance else data.get("device") for vlan in data.get("tagged_vlans", []): if vlan.site not in [device.site, None]: raise serializers.ValidationError({ "tagged_vlans": f"VLAN {vlan} must belong to the same site as the interface's parent device, or " f"it must be global." }) return super().validate(data)
class DeviceSerializer(TaggedObjectSerializer, StatusModelSerializerMixin, CustomFieldModelSerializer): url = serializers.HyperlinkedIdentityField( view_name="dcim-api:device-detail") device_type = NestedDeviceTypeSerializer() device_role = NestedDeviceRoleSerializer() tenant = NestedTenantSerializer(required=False, allow_null=True) platform = NestedPlatformSerializer(required=False, allow_null=True) site = NestedSiteSerializer() rack = NestedRackSerializer(required=False, allow_null=True) face = ChoiceField(choices=DeviceFaceChoices, allow_blank=True, required=False) primary_ip = NestedIPAddressSerializer(read_only=True) primary_ip4 = NestedIPAddressSerializer(required=False, allow_null=True) primary_ip6 = NestedIPAddressSerializer(required=False, allow_null=True) parent_device = serializers.SerializerMethodField() cluster = NestedClusterSerializer(required=False, allow_null=True) virtual_chassis = NestedVirtualChassisSerializer(required=False, allow_null=True) local_context_schema = NestedConfigContextSchemaSerializer(required=False, allow_null=True) class Meta: model = Device fields = [ "id", "url", "name", "device_type", "device_role", "tenant", "platform", "serial", "asset_tag", "site", "rack", "position", "face", "parent_device", "status", "primary_ip", "primary_ip4", "primary_ip6", "cluster", "virtual_chassis", "vc_position", "vc_priority", "comments", "local_context_schema", "local_context_data", "tags", "custom_fields", "created", "last_updated", "computed_fields", ] opt_in_fields = ["computed_fields"] validators = [] def validate(self, data): # Validate uniqueness of (rack, position, face) since we omitted the automatically-created validator from Meta. if data.get("rack") and data.get("position") and data.get("face"): validator = UniqueTogetherValidator(queryset=Device.objects.all(), fields=("rack", "position", "face")) validator(data, self) # Enforce model validation super().validate(data) return data @swagger_serializer_method(serializer_or_field=NestedDeviceSerializer) 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