rcnn/backend/apps/challenges/serializers.py
2026-04-21 16:33:15 +02:00

105 lines
3.4 KiB
Python

from rest_framework import serializers
from rest_framework_gis.fields import GeometryField
from rest_framework_gis.serializers import GeoFeatureModelSerializer
from apps.utils.storage import preview_url
from .models import Challenge, ChallengeParticipant
class ChallengeCreateSerializer(serializers.ModelSerializer):
# Accepts GeoJSON Polygon from the client
region = GeometryField(precision=6)
class Meta:
model = Challenge
fields = ["title", "description", "region", "max_submissions", "expires_at"]
def validate_region(self, value):
if value.geom_type != "Polygon":
raise serializers.ValidationError("region must be a GeoJSON Polygon.")
return value
class ChallengeUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Challenge
fields = ["title", "description", "expires_at", "status"]
class ChallengeMapSerializer(GeoFeatureModelSerializer):
"""
GeoJSON FeatureCollection using region_centroid as geometry.
Used for the map pin list — does not include the full region polygon.
"""
class Meta:
model = Challenge
geo_field = "region_centroid"
fields = [
"id", "title", "status",
"submission_count", "max_submissions",
"expires_at", "created_at",
]
class ChallengeSplatPreviewSerializer(serializers.Serializer):
id = serializers.UUIDField()
preview_url = serializers.SerializerMethodField()
created_at = serializers.DateTimeField()
def get_preview_url(self, obj):
return preview_url(obj.preview_key)
class ChallengeDetailSerializer(serializers.ModelSerializer):
region = serializers.SerializerMethodField()
region_centroid = serializers.SerializerMethodField()
creator_username = serializers.CharField(source="creator.username", read_only=True)
participant_count = serializers.SerializerMethodField()
is_participating = serializers.SerializerMethodField()
preview_splats = serializers.SerializerMethodField()
class Meta:
model = Challenge
fields = [
"id", "title", "description", "status",
"creator_username",
"region", "region_centroid",
"max_submissions", "submission_count",
"participant_count", "is_participating",
"preview_splats",
"expires_at", "created_at", "updated_at",
]
def get_region(self, obj):
import json
return json.loads(obj.region.geojson) if obj.region else None
def get_region_centroid(self, obj):
import json
return json.loads(obj.region_centroid.geojson) if obj.region_centroid else None
def get_participant_count(self, obj):
return obj.participants.count()
def get_is_participating(self, obj):
request = self.context.get("request")
if not request or not request.user.is_authenticated:
return False
return obj.participants.filter(user=request.user).exists()
def get_preview_splats(self, obj):
from apps.splats.models import Splat
qs = (
Splat.objects.filter(challenge=obj, is_published=True)
.order_by("-created_at")[:5]
)
return ChallengeSplatPreviewSerializer(qs, many=True).data
class ChallengeParticipantSerializer(serializers.ModelSerializer):
class Meta:
model = ChallengeParticipant
fields = ["id", "joined_at"]
read_only_fields = fields