mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 08:31:08 -05:00
- Add complete backend/ directory with full Django application - Add frontend/ directory with Vite + TypeScript setup ready for Next.js - Add comprehensive shared/ directory with: - Complete documentation and memory-bank archives - Media files and avatars (letters, park/ride images) - Deployment scripts and automation tools - Shared types and utilities - Add architecture/ directory with migration guides - Configure pnpm workspace for monorepo development - Update .gitignore to exclude .django_tailwind_cli/ build artifacts - Preserve all historical documentation in shared/docs/memory-bank/ - Set up proper structure for full-stack development with shared resources
346 lines
11 KiB
Python
346 lines
11 KiB
Python
"""
|
|
Serializers for Rides API following Django styleguide patterns.
|
|
"""
|
|
|
|
from rest_framework import serializers
|
|
from ..models import Ride
|
|
|
|
|
|
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()
|