rcnn/backend/apps/splats/serializers.py
Marius Unsel d93412cd0d Initial commit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 01:12:40 +02:00

110 lines
3.6 KiB
Python

from django.conf import settings
from django.utils import timezone
from rest_framework import serializers
from rest_framework_gis.serializers import GeoFeatureModelSerializer
from apps.utils.storage import generate_presigned_put_url, preview_url
from .models import Splat
class SplatJobSummarySerializer(serializers.Serializer):
"""Inlined job status — used in SplatMineSerializer."""
id = serializers.UUIDField()
status = serializers.CharField()
current_step = serializers.CharField()
progress = serializers.IntegerField()
error_message = serializers.CharField()
queued_at = serializers.DateTimeField()
started_at = serializers.DateTimeField()
finished_at = serializers.DateTimeField()
class SplatCreateSerializer(serializers.ModelSerializer):
challenge_id = serializers.UUIDField(required=False, allow_null=True)
capture_metadata = serializers.JSONField()
class Meta:
model = Splat
fields = ["challenge_id", "capture_metadata"]
def validate_capture_metadata(self, value):
frames = value.get("frames", [])
min_frames = settings.MIN_CAPTURE_FRAMES
if len(frames) < min_frames:
raise serializers.ValidationError(
f"capture_metadata must contain at least {min_frames} frames; "
f"got {len(frames)}."
)
return value
class SplatCreateResponseSerializer(serializers.Serializer):
"""Shape of the POST /splats/ response — not a ModelSerializer."""
id = serializers.UUIDField()
status = serializers.CharField()
upload_url = serializers.CharField(allow_null=True)
upload_expires_at = serializers.DateTimeField()
class SplatMapSerializer(GeoFeatureModelSerializer):
"""GeoJSON FeatureCollection for the map tile endpoint."""
preview_url = serializers.SerializerMethodField()
class Meta:
model = Splat
geo_field = "location"
fields = ["id", "heading", "altitude", "preview_url", "splat_file_size", "created_at"]
def get_preview_url(self, obj):
return preview_url(obj.preview_key)
class SplatDetailSerializer(serializers.ModelSerializer):
coverage = serializers.SerializerMethodField()
preview_url = serializers.SerializerMethodField()
owner_username = serializers.CharField(source="owner.username", read_only=True)
challenge_id = serializers.UUIDField(read_only=True)
class Meta:
model = Splat
fields = [
"id", "owner_username", "challenge_id", "status", "is_published",
"location", "coverage", "heading", "altitude",
"preview_url", "splat_file_size",
"quality_score", "frame_count",
"created_at", "updated_at",
]
def get_coverage(self, obj):
if obj.coverage:
return obj.coverage.geojson
return None
def get_preview_url(self, obj):
return preview_url(obj.preview_key)
class SplatMineSerializer(serializers.ModelSerializer):
job = serializers.SerializerMethodField()
preview_url = serializers.SerializerMethodField()
class Meta:
model = Splat
fields = [
"id", "status", "is_published",
"challenge_id", "preview_url",
"quality_score", "frame_count",
"created_at", "updated_at",
"job",
]
def get_job(self, obj):
try:
j = obj.job
except Splat.job.RelatedObjectDoesNotExist:
return None
return SplatJobSummarySerializer(j).data
def get_preview_url(self, obj):
return preview_url(obj.preview_key)