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 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)