""" Serializers for Rides API following Django styleguide patterns. """ from rest_framework import serializers from ..models import Ride, RideModel, Company class RideModelOutputSerializer(serializers.Serializer): """Output serializer for ride model data.""" id = serializers.IntegerField() name = serializers.CharField() description = serializers.CharField() category = serializers.CharField() manufacturer = serializers.SerializerMethodField() def get_manufacturer(self, obj): if obj.manufacturer: return { 'id': obj.manufacturer.id, 'name': obj.manufacturer.name, 'slug': obj.manufacturer.slug } return None class RideParkOutputSerializer(serializers.Serializer): """Output serializer for ride's park data.""" id = serializers.IntegerField() name = serializers.CharField() slug = serializers.CharField() class RideListOutputSerializer(serializers.Serializer): """Output serializer for ride list view.""" id = serializers.IntegerField() name = serializers.CharField() slug = serializers.CharField() category = serializers.CharField() status = serializers.CharField() description = serializers.CharField() # Park info park = RideParkOutputSerializer() # Statistics average_rating = serializers.DecimalField(max_digits=3, decimal_places=2, allow_null=True) capacity_per_hour = serializers.IntegerField(allow_null=True) # Dates opening_date = serializers.DateField(allow_null=True) closing_date = serializers.DateField(allow_null=True) # Metadata created_at = serializers.DateTimeField() updated_at = serializers.DateTimeField() class RideDetailOutputSerializer(serializers.Serializer): """Output serializer for ride detail view.""" id = serializers.IntegerField() name = serializers.CharField() slug = serializers.CharField() category = serializers.CharField() status = serializers.CharField() post_closing_status = serializers.CharField(allow_null=True) description = serializers.CharField() # Park info park = RideParkOutputSerializer() park_area = serializers.SerializerMethodField() # Dates opening_date = serializers.DateField(allow_null=True) closing_date = serializers.DateField(allow_null=True) status_since = serializers.DateField(allow_null=True) # Physical specs min_height_in = serializers.IntegerField(allow_null=True) max_height_in = serializers.IntegerField(allow_null=True) capacity_per_hour = serializers.IntegerField(allow_null=True) ride_duration_seconds = serializers.IntegerField(allow_null=True) # Statistics average_rating = serializers.DecimalField(max_digits=3, decimal_places=2, allow_null=True) # Companies manufacturer = serializers.SerializerMethodField() designer = serializers.SerializerMethodField() # Model ride_model = RideModelOutputSerializer(allow_null=True) # Metadata created_at = serializers.DateTimeField() updated_at = serializers.DateTimeField() def get_park_area(self, obj): if obj.park_area: return { 'id': obj.park_area.id, 'name': obj.park_area.name, 'slug': obj.park_area.slug } return None def get_manufacturer(self, obj): if obj.manufacturer: return { 'id': obj.manufacturer.id, 'name': obj.manufacturer.name, 'slug': obj.manufacturer.slug } return None def get_designer(self, obj): if obj.designer: return { 'id': obj.designer.id, 'name': obj.designer.name, 'slug': obj.designer.slug } return None class RideCreateInputSerializer(serializers.Serializer): """Input serializer for creating rides.""" name = serializers.CharField(max_length=255) description = serializers.CharField(allow_blank=True, default="") category = serializers.ChoiceField(choices=Ride.CATEGORY_CHOICES) status = serializers.ChoiceField( choices=Ride.STATUS_CHOICES, default="OPERATING" ) # Required park park_id = serializers.IntegerField() # Optional area park_area_id = serializers.IntegerField(required=False, allow_null=True) # Optional dates opening_date = serializers.DateField(required=False, allow_null=True) closing_date = serializers.DateField(required=False, allow_null=True) status_since = serializers.DateField(required=False, allow_null=True) # Optional specs min_height_in = serializers.IntegerField( required=False, allow_null=True, min_value=30, max_value=90 ) max_height_in = serializers.IntegerField( required=False, allow_null=True, min_value=30, max_value=90 ) capacity_per_hour = serializers.IntegerField( required=False, allow_null=True, min_value=1 ) ride_duration_seconds = serializers.IntegerField( required=False, allow_null=True, min_value=1 ) # Optional companies manufacturer_id = serializers.IntegerField(required=False, allow_null=True) designer_id = serializers.IntegerField(required=False, allow_null=True) # Optional model ride_model_id = serializers.IntegerField(required=False, allow_null=True) def validate(self, data): """Cross-field validation.""" # Date validation opening_date = data.get('opening_date') closing_date = data.get('closing_date') if opening_date and closing_date and closing_date < opening_date: raise serializers.ValidationError( "Closing date cannot be before opening date" ) # Height validation min_height = data.get('min_height_in') max_height = data.get('max_height_in') if min_height and max_height and min_height > max_height: raise serializers.ValidationError( "Minimum height cannot be greater than maximum height" ) return data class RideUpdateInputSerializer(serializers.Serializer): """Input serializer for updating rides.""" name = serializers.CharField(max_length=255, required=False) description = serializers.CharField(allow_blank=True, required=False) category = serializers.ChoiceField(choices=Ride.CATEGORY_CHOICES, required=False) status = serializers.ChoiceField(choices=Ride.STATUS_CHOICES, required=False) post_closing_status = serializers.ChoiceField( choices=Ride.POST_CLOSING_STATUS_CHOICES, required=False, allow_null=True ) # Park and area park_id = serializers.IntegerField(required=False) park_area_id = serializers.IntegerField(required=False, allow_null=True) # Dates opening_date = serializers.DateField(required=False, allow_null=True) closing_date = serializers.DateField(required=False, allow_null=True) status_since = serializers.DateField(required=False, allow_null=True) # Specs min_height_in = serializers.IntegerField( required=False, allow_null=True, min_value=30, max_value=90 ) max_height_in = serializers.IntegerField( required=False, allow_null=True, min_value=30, max_value=90 ) capacity_per_hour = serializers.IntegerField( required=False, allow_null=True, min_value=1 ) ride_duration_seconds = serializers.IntegerField( required=False, allow_null=True, min_value=1 ) # Companies manufacturer_id = serializers.IntegerField(required=False, allow_null=True) designer_id = serializers.IntegerField(required=False, allow_null=True) # Model ride_model_id = serializers.IntegerField(required=False, allow_null=True) def validate(self, data): """Cross-field validation.""" # Date validation opening_date = data.get('opening_date') closing_date = data.get('closing_date') if opening_date and closing_date and closing_date < opening_date: raise serializers.ValidationError( "Closing date cannot be before opening date" ) # Height validation min_height = data.get('min_height_in') max_height = data.get('max_height_in') if min_height and max_height and min_height > max_height: raise serializers.ValidationError( "Minimum height cannot be greater than maximum height" ) return data class RideFilterInputSerializer(serializers.Serializer): """Input serializer for ride filtering and search.""" # Search search = serializers.CharField(required=False, allow_blank=True) # Category filter category = serializers.MultipleChoiceField( choices=Ride.CATEGORY_CHOICES, required=False ) # Status filter status = serializers.MultipleChoiceField( choices=Ride.STATUS_CHOICES, required=False ) # Park filter park_id = serializers.IntegerField(required=False) park_slug = serializers.CharField(required=False, allow_blank=True) # Company filters manufacturer_id = serializers.IntegerField(required=False) designer_id = serializers.IntegerField(required=False) # Rating filter min_rating = serializers.DecimalField( max_digits=3, decimal_places=2, required=False, min_value=1, max_value=10 ) # Height filters min_height_requirement = serializers.IntegerField(required=False) max_height_requirement = serializers.IntegerField(required=False) # Capacity filter min_capacity = serializers.IntegerField(required=False) # Ordering ordering = serializers.ChoiceField( choices=[ 'name', '-name', 'opening_date', '-opening_date', 'average_rating', '-average_rating', 'capacity_per_hour', '-capacity_per_hour', 'created_at', '-created_at' ], required=False, default='name' ) class RideStatsOutputSerializer(serializers.Serializer): """Output serializer for ride statistics.""" total_rides = serializers.IntegerField() operating_rides = serializers.IntegerField() closed_rides = serializers.IntegerField() under_construction = serializers.IntegerField() # By category rides_by_category = serializers.DictField() # Averages average_rating = serializers.DecimalField(max_digits=3, decimal_places=2, allow_null=True) average_capacity = serializers.DecimalField(max_digits=8, decimal_places=2, allow_null=True) # Top manufacturers top_manufacturers = serializers.ListField(child=serializers.DictField()) # Recently added recently_added_count = serializers.IntegerField()