128 lines
5 KiB
Python
128 lines
5 KiB
Python
from rest_framework import serializers
|
||
from .models import Prediction, SavedPoint, SavedRateProfile, PreditctionTemplate
|
||
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']
|
||
read_only_fields = ['id']
|
||
|
||
|
||
class SavedPointSerializer(serializers.ModelSerializer):
|
||
user = serializers.HiddenField(
|
||
default=serializers.CurrentUserDefault()
|
||
)
|
||
class Meta:
|
||
model = SavedPoint
|
||
fields = ['user', 'id', 'name', 'lat', 'lon', 'alt']
|
||
read_only_fields = ['id']
|
||
|
||
validators = [
|
||
serializers.UniqueTogetherValidator(
|
||
queryset=SavedPoint.objects.all(),
|
||
fields=['user', 'name'],
|
||
message="A saved point with this name already exists for the user."
|
||
)
|
||
]
|
||
|
||
|
||
|
||
class SavedRateProfileSerializer(serializers.ModelSerializer):
|
||
class Meta:
|
||
model = SavedRateProfile
|
||
fields = ['id', 'name', 'rate_profile_data']
|
||
read_only_fields = ['id']
|
||
|
||
|
||
class PreditctionTemplateSerializer(serializers.ModelSerializer):
|
||
class Meta:
|
||
model = PreditctionTemplate
|
||
fields = ['id', 'name', 'template_data', 'is_default']
|
||
read_only_fields = ['id']
|