initial commit
This commit is contained in:
commit
c6961c03c3
33 changed files with 1782 additions and 0 deletions
185
stratoflights_api/serializers.py
Normal file
185
stratoflights_api/serializers.py
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
from rest_framework import serializers
|
||||
from .models import Prediction, SavedPoint, SavedRateProfile, PreditctionTemplate
|
||||
from datetime import datetime
|
||||
from django.contrib.auth.password_validation import validate_password
|
||||
from django.core.validators import validate_email
|
||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
||||
from django.contrib.auth import get_user_model
|
||||
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']
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
PROFILE_STANDARD = "standard_profile"
|
||||
PROFILE_FLOAT = "float_profile"
|
||||
PROFILE_REVERSE = "reverse_profile"
|
||||
PROFILE_CUSTOM = "custom_profile"
|
||||
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)
|
||||
start_point = serializers.PrimaryKeyRelatedField(
|
||||
queryset=SavedPoint.objects.all(), required=False, allow_null=True
|
||||
)
|
||||
rate_profile = serializers.PrimaryKeyRelatedField(
|
||||
queryset=SavedRateProfile.objects.all(), required=False, allow_null=True
|
||||
)
|
||||
template = serializers.PrimaryKeyRelatedField(
|
||||
queryset=PreditctionTemplate.objects.all(), required=False, allow_null=True
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
def create(self, validated_data):
|
||||
if 'ascent_curve' in validated_data:
|
||||
validated_data['ascent_curve'] = base64_to_curve(validated_data['ascent_curve'])
|
||||
if 'descent_curve' in validated_data:
|
||||
validated_data['descent_curve'] = base64_to_curve(validated_data['descent_curve'])
|
||||
|
||||
prediction = Prediction(
|
||||
user=validated_data.get('user'),
|
||||
request=validated_data.get('request', {}),
|
||||
result=validated_data.get('result', {}),
|
||||
start_point=validated_data.get('start_point'),
|
||||
template=validated_data.get('template'),
|
||||
rate_profile=validated_data.get('rate_profile')
|
||||
)
|
||||
prediction.save()
|
||||
|
||||
return prediction
|
||||
|
||||
|
||||
class PredictionListSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Prediction
|
||||
fields = ["id", "created_at", "updated_at", "start_point", "template", "rate_profile"]
|
||||
|
||||
|
||||
class PredictionDetailSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Prediction
|
||||
fields = ["id", "created_at", "updated_at", "result", "start_point", "template", "rate_profile"]
|
||||
|
||||
|
||||
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', 'type', 'rate_profile_data']
|
||||
read_only_fields = ['id']
|
||||
|
||||
|
||||
class PreditctionTemplateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = PreditctionTemplate
|
||||
fields = ['id', 'name', 'is_default', 'description', 'prediction_mode', 'model', 'dataset', 'flight_parameters']
|
||||
read_only_fields = ['id']
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['username', 'email', 'first_name', 'last_name']
|
||||
extra_kwargs = {
|
||||
'username': {'read_only': True}
|
||||
}
|
||||
|
||||
def validate_email(self, value):
|
||||
try:
|
||||
validate_email(value)
|
||||
except DjangoValidationError:
|
||||
raise serializers.ValidationError("Invalid email format")
|
||||
return value
|
||||
|
||||
class ChangePasswordSerializer(serializers.Serializer):
|
||||
old_password = serializers.CharField(required=True)
|
||||
new_password = serializers.CharField(required=True)
|
||||
|
||||
def validate_new_password(self, value):
|
||||
validate_password(value)
|
||||
return value
|
||||
|
||||
class DeleteAccountSerializer(serializers.Serializer):
|
||||
password = serializers.CharField(required=True)
|
||||
Loading…
Add table
Add a link
Reference in a new issue