From 96a4860d79c6f0c6188458e17d8efd8f79186d1c Mon Sep 17 00:00:00 2001 From: OlhaZahoruiko Date: Mon, 6 Oct 2025 16:46:55 +0200 Subject: [PATCH] :memo: [#667] Improve typing information in API schema --- src/objects/api/serializers.py | 229 ++++++++++++++++++++++----------- 1 file changed, 155 insertions(+), 74 deletions(-) diff --git a/src/objects/api/serializers.py b/src/objects/api/serializers.py index 74d898a9..e1a960e1 100644 --- a/src/objects/api/serializers.py +++ b/src/objects/api/serializers.py @@ -15,6 +15,87 @@ logger = structlog.stdlib.get_logger(__name__) +class ObjectSerializer(DynamicFieldsMixin, serializers.HyperlinkedModelSerializer): + url = CachedObjectUrlField(view_name="object-detail") + uuid = serializers.UUIDField( + source="object.uuid", + required=False, + validators=[IsImmutableValidator()], + help_text=_("Unique identifier (UUID4)"), + ) + + type = ObjectTypeField( + min_length=1, + max_length=1000, + source="object.object_type", + queryset=ObjectType.objects.all(), + help_text=_("Url reference to OBJECTTYPE in Objecttypes API"), + validators=[IsImmutableValidator()], + ) + + type_detail = ObjectTypeSerializer( + source="object.object_type", + read_only=True, + help_text=_("Full object type details") + ) + + record = ObjectRecordSerializer( + source="*", help_text=_("State of the OBJECT at a certain time") + ) + + class Meta: + model = ObjectRecord + fields = ("url", "uuid", "type", "type_detail", "record") + extra_kwargs = { + "url": {"lookup_field": "object.uuid"}, + } + validators = [JsonSchemaValidator(), GeometryValidator()] + + @transaction.atomic + def create(self, validated_data): + object_data = validated_data.pop("object") + object = Object.objects.create(**object_data) + + validated_data["object"] = object + record = super().create(validated_data) + token_auth: TokenAuth = self.context["request"].auth + logger.info( + "object_created", + object_uuid=str(object.uuid), + objecttype_uuid=str(object.object_type.uuid), + objecttype_version=record.version, + token_identifier=token_auth.identifier, + token_application=token_auth.application, + ) + return record + + @transaction.atomic + def update(self, instance, validated_data): + validated_data.pop("object", None) + validated_data["object"] = instance.object + + if "version" not in validated_data: + validated_data["version"] = instance.version + if "start_at" not in validated_data: + validated_data["start_at"] = instance.start_at + + if self.partial and "data" in validated_data: + validated_data["data"] = merge_patch(instance.data, validated_data["data"]) + + record = super().create(validated_data) + token_auth: TokenAuth = self.context["request"].auth + logger.info( + "object_updated", + object_uuid=str(record.object.uuid), + objecttype_uuid=str(record.object.object_type.uuid), + objecttype_version=record.version, + token_identifier=token_auth.identifier, + token_application=token_auth.application, + ) + return record + + + class ObjectRecordSerializer(serializers.ModelSerializer): correctionFor = ObjectSlugRelatedField( @@ -88,80 +169,80 @@ class Meta: "registrationAt": {"source": "registration_at", "read_only": True}, } - -class ObjectSerializer(DynamicFieldsMixin, serializers.HyperlinkedModelSerializer): - url = CachedObjectUrlField(view_name="object-detail") - uuid = serializers.UUIDField( - source="object.uuid", - required=False, - validators=[IsImmutableValidator()], - help_text=_("Unique identifier (UUID4)"), - ) - type = ObjectTypeField( - min_length=1, - max_length=1000, - source="object.object_type", - queryset=ObjectType.objects.all(), - help_text=_("Url reference to OBJECTTYPE in Objecttypes API"), - validators=[IsImmutableValidator()], - ) - record = ObjectRecordSerializer( - source="*", help_text=_("State of the OBJECT at a certain time") - ) - - class Meta: - model = ObjectRecord - fields = ("url", "uuid", "type", "record") - extra_kwargs = { - "url": {"lookup_field": "object.uuid"}, - } - validators = [JsonSchemaValidator(), GeometryValidator()] - - @transaction.atomic - def create(self, validated_data): - object_data = validated_data.pop("object") - object = Object.objects.create(**object_data) - - validated_data["object"] = object - record = super().create(validated_data) - token_auth: TokenAuth = self.context["request"].auth - logger.info( - "object_created", - object_uuid=str(object.uuid), - objecttype_uuid=str(object.object_type.uuid), - objecttype_version=record.version, - token_identifier=token_auth.identifier, - token_application=token_auth.application, - ) - return record - - @transaction.atomic - def update(self, instance, validated_data): - # object_data is not used since all object attributes are immutable - validated_data.pop("object", None) - validated_data["object"] = instance.object - # version should be set - if "version" not in validated_data: - validated_data["version"] = instance.version - # start_at should be set - if "start_at" not in validated_data: - validated_data["start_at"] = instance.start_at - - if self.partial and "data" in validated_data: - # Apply JSON Merge Patch for record data - validated_data["data"] = merge_patch(instance.data, validated_data["data"]) - - record = super().create(validated_data) - token_auth: TokenAuth = self.context["request"].auth - logger.info( - "object_updated", - object_uuid=str(record.object.uuid), - objecttype_uuid=str(record.object.object_type.uuid), - objecttype_version=record.version, - token_identifier=token_auth.identifier, - token_application=token_auth.application, - ) - return record +# +# class ObjectSerializer(DynamicFieldsMixin, serializers.HyperlinkedModelSerializer): +# url = CachedObjectUrlField(view_name="object-detail") +# uuid = serializers.UUIDField( +# source="object.uuid", +# required=False, +# validators=[IsImmutableValidator()], +# help_text=_("Unique identifier (UUID4)"), +# ) +# type = ObjectTypeField( +# min_length=1, +# max_length=1000, +# source="object.object_type", +# queryset=ObjectType.objects.all(), +# help_text=_("Url reference to OBJECTTYPE in Objecttypes API"), +# validators=[IsImmutableValidator()], +# ) +# record = ObjectRecordSerializer( +# source="*", help_text=_("State of the OBJECT at a certain time") +# ) +# +# class Meta: +# model = ObjectRecord +# fields = ("url", "uuid", "type", "record") +# extra_kwargs = { +# "url": {"lookup_field": "object.uuid"}, +# } +# validators = [JsonSchemaValidator(), GeometryValidator()] +# +# @transaction.atomic +# def create(self, validated_data): +# object_data = validated_data.pop("object") +# object = Object.objects.create(**object_data) +# +# validated_data["object"] = object +# record = super().create(validated_data) +# token_auth: TokenAuth = self.context["request"].auth +# logger.info( +# "object_created", +# object_uuid=str(object.uuid), +# objecttype_uuid=str(object.object_type.uuid), +# objecttype_version=record.version, +# token_identifier=token_auth.identifier, +# token_application=token_auth.application, +# ) +# return record +# +# @transaction.atomic +# def update(self, instance, validated_data): +# # object_data is not used since all object attributes are immutable +# validated_data.pop("object", None) +# validated_data["object"] = instance.object +# # version should be set +# if "version" not in validated_data: +# validated_data["version"] = instance.version +# # start_at should be set +# if "start_at" not in validated_data: +# validated_data["start_at"] = instance.start_at +# +# if self.partial and "data" in validated_data: +# # Apply JSON Merge Patch for record data +# validated_data["data"] = merge_patch(instance.data, validated_data["data"]) +# +# record = super().create(validated_data) +# token_auth: TokenAuth = self.context["request"].auth +# logger.info( +# "object_updated", +# object_uuid=str(record.object.uuid), +# objecttype_uuid=str(record.object.object_type.uuid), +# objecttype_version=record.version, +# token_identifier=token_auth.identifier, +# token_application=token_auth.application, +# ) +# return record class GeoWithinSerializer(serializers.Serializer):