mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 17:11:09 -05:00
feat: complete monorepo structure with frontend and shared resources
- 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
This commit is contained in:
345
backend/apps/rides/api/serializers.py
Normal file
345
backend/apps/rides/api/serializers.py
Normal file
@@ -0,0 +1,345 @@
|
||||
"""
|
||||
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()
|
||||
Reference in New Issue
Block a user