from rest_framework import serializers from .models import Prediction from datetime import datetime from .validators import ( validate_custom_curve, rate_clip, _rfc3339_to_timestamp, base64_to_curve ) class PredictionSerializer(serializers.ModelSerializer): class Meta: model = Prediction fields = ['id', 'created_at', 'updated_at', 'result'] PROFILE_STANDARD = "standard_profile" PROFILE_FLOAT = "float" PROFILE_REVERSE = "reverse" PROFILE_CUSTOM = "custom" LATEST_DATASET_KEYWORD = "latest" SUPPORTED_PROFILES = [PROFILE_STANDARD, PROFILE_FLOAT, PROFILE_REVERSE, PROFILE_CUSTOM] class PredictionRequestSerializer(serializers.Serializer): launch_latitude = serializers.FloatField(min_value=-90, max_value=90) launch_longitude = serializers.FloatField(min_value=0, max_value=360) launch_datetime = serializers.DateTimeField() launch_altitude = serializers.FloatField(required=False) format = serializers.CharField(default="json") profile = serializers.ChoiceField(choices=SUPPORTED_PROFILES, default=PROFILE_STANDARD) dataset = serializers.CharField(default=LATEST_DATASET_KEYWORD) # --- профиль-dependent поля --- ascent_rate = serializers.FloatField(required=False, min_value=0.01) descent_rate = serializers.FloatField(required=False, min_value=0.01) burst_altitude = serializers.FloatField(required=False) float_altitude = serializers.FloatField(required=False) stop_datetime = serializers.DateTimeField(required=False) ascent_curve = serializers.CharField(required=False) descent_curve = serializers.CharField(required=False) interpolate = serializers.BooleanField(required=False, default=False) def validate(self, data): profile = data.get("profile", PROFILE_STANDARD) launch_alt = data.get("launch_altitude", 0) if profile == PROFILE_STANDARD: if 'burst_altitude' not in data: raise serializers.ValidationError("burst_altitude is required for standard profile.") if data['burst_altitude'] <= launch_alt: raise serializers.ValidationError("burst_altitude must be greater than launch_altitude.") elif profile == PROFILE_FLOAT: if 'float_altitude' not in data or data['float_altitude'] <= launch_alt: raise serializers.ValidationError("float_altitude must be greater than launch_altitude.") if 'stop_datetime' not in data or data['stop_datetime'] <= data['launch_datetime']: raise serializers.ValidationError("stop_datetime must be later than launch_datetime.") elif profile == PROFILE_CUSTOM: if 'ascent_curve' not in data or not validate_custom_curve(data['ascent_curve']): raise serializers.ValidationError("Invalid ascent_curve.") if 'descent_curve' not in data or not validate_custom_curve(data['descent_curve']): raise serializers.ValidationError("Invalid descent_curve.") if 'burst_altitude' not in data or data['burst_altitude'] <= launch_alt: raise serializers.ValidationError("burst_altitude must be greater than launch_altitude.") # кастомная логика clipping'а if 'ascent_rate' in data: data['ascent_rate'] = rate_clip(data['ascent_rate']) if 'descent_rate' in data: data['descent_rate'] = rate_clip(data['descent_rate']) return data class PredictionListSerializer(serializers.ModelSerializer): class Meta: model = Prediction fields = ["id", "created_at", "updated_at"] class PredictionDetailSerializer(serializers.ModelSerializer): class Meta: model = Prediction fields = ["id", "created_at", "updated_at", "result"] from rest_framework import serializers from .models import TelemetryPacket class TelemetryPacketSerializer(serializers.ModelSerializer): class Meta: model = TelemetryPacket fields = ['id', 'timestamp', 'lat', 'lon', 'alt', 'payload']