mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 18:31:09 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
448
backend/apps/api/v1/serializers/parks.py
Normal file
448
backend/apps/api/v1/serializers/parks.py
Normal file
@@ -0,0 +1,448 @@
|
||||
"""
|
||||
Parks domain serializers for ThrillWiki API v1.
|
||||
|
||||
This module contains all serializers related to parks, park areas, park locations,
|
||||
and park search functionality.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from drf_spectacular.utils import (
|
||||
extend_schema_serializer,
|
||||
extend_schema_field,
|
||||
OpenApiExample,
|
||||
)
|
||||
|
||||
from .shared import LocationOutputSerializer, CompanyOutputSerializer, ModelChoices
|
||||
|
||||
|
||||
# === PARK SERIALIZERS ===
|
||||
|
||||
|
||||
@extend_schema_serializer(
|
||||
examples=[
|
||||
OpenApiExample(
|
||||
"Park List Example",
|
||||
summary="Example park list response",
|
||||
description="A typical park in the list view",
|
||||
value={
|
||||
"id": 1,
|
||||
"name": "Cedar Point",
|
||||
"slug": "cedar-point",
|
||||
"status": "OPERATING",
|
||||
"description": "America's Roller Coast",
|
||||
"average_rating": 4.5,
|
||||
"coaster_count": 17,
|
||||
"ride_count": 70,
|
||||
"location": {
|
||||
"city": "Sandusky",
|
||||
"state": "Ohio",
|
||||
"country": "United States",
|
||||
},
|
||||
"operator": {"id": 1, "name": "Cedar Fair", "slug": "cedar-fair"},
|
||||
},
|
||||
)
|
||||
]
|
||||
)
|
||||
class ParkListOutputSerializer(serializers.Serializer):
|
||||
"""Output serializer for park list view."""
|
||||
|
||||
id = serializers.IntegerField()
|
||||
name = serializers.CharField()
|
||||
slug = serializers.CharField()
|
||||
status = serializers.CharField()
|
||||
description = serializers.CharField()
|
||||
|
||||
# Statistics
|
||||
average_rating = serializers.DecimalField(
|
||||
max_digits=3, decimal_places=2, allow_null=True
|
||||
)
|
||||
coaster_count = serializers.IntegerField(allow_null=True)
|
||||
ride_count = serializers.IntegerField(allow_null=True)
|
||||
|
||||
# Location (simplified for list view)
|
||||
location = LocationOutputSerializer(allow_null=True)
|
||||
|
||||
# Operator info
|
||||
operator = CompanyOutputSerializer()
|
||||
|
||||
# Metadata
|
||||
created_at = serializers.DateTimeField()
|
||||
updated_at = serializers.DateTimeField()
|
||||
|
||||
|
||||
@extend_schema_serializer(
|
||||
examples=[
|
||||
OpenApiExample(
|
||||
"Park Detail Example",
|
||||
summary="Example park detail response",
|
||||
description="A complete park detail response",
|
||||
value={
|
||||
"id": 1,
|
||||
"name": "Cedar Point",
|
||||
"slug": "cedar-point",
|
||||
"status": "OPERATING",
|
||||
"description": "America's Roller Coast",
|
||||
"opening_date": "1870-01-01",
|
||||
"website": "https://cedarpoint.com",
|
||||
"size_acres": 364.0,
|
||||
"average_rating": 4.5,
|
||||
"coaster_count": 17,
|
||||
"ride_count": 70,
|
||||
"location": {
|
||||
"latitude": 41.4793,
|
||||
"longitude": -82.6833,
|
||||
"city": "Sandusky",
|
||||
"state": "Ohio",
|
||||
"country": "United States",
|
||||
},
|
||||
"operator": {"id": 1, "name": "Cedar Fair", "slug": "cedar-fair"},
|
||||
},
|
||||
)
|
||||
]
|
||||
)
|
||||
class ParkDetailOutputSerializer(serializers.Serializer):
|
||||
"""Output serializer for park detail view."""
|
||||
|
||||
id = serializers.IntegerField()
|
||||
name = serializers.CharField()
|
||||
slug = serializers.CharField()
|
||||
status = serializers.CharField()
|
||||
description = serializers.CharField()
|
||||
|
||||
# Details
|
||||
opening_date = serializers.DateField(allow_null=True)
|
||||
closing_date = serializers.DateField(allow_null=True)
|
||||
operating_season = serializers.CharField()
|
||||
size_acres = serializers.DecimalField(
|
||||
max_digits=10, decimal_places=2, allow_null=True
|
||||
)
|
||||
website = serializers.URLField()
|
||||
|
||||
# Statistics
|
||||
average_rating = serializers.DecimalField(
|
||||
max_digits=3, decimal_places=2, allow_null=True
|
||||
)
|
||||
coaster_count = serializers.IntegerField(allow_null=True)
|
||||
ride_count = serializers.IntegerField(allow_null=True)
|
||||
|
||||
# Location (full details)
|
||||
location = LocationOutputSerializer(allow_null=True)
|
||||
|
||||
# Companies
|
||||
operator = CompanyOutputSerializer()
|
||||
property_owner = CompanyOutputSerializer(allow_null=True)
|
||||
|
||||
# Areas
|
||||
areas = serializers.SerializerMethodField()
|
||||
|
||||
@extend_schema_field(serializers.ListField(child=serializers.DictField()))
|
||||
def get_areas(self, obj):
|
||||
"""Get simplified area information."""
|
||||
if hasattr(obj, "areas"):
|
||||
return [
|
||||
{
|
||||
"id": area.id,
|
||||
"name": area.name,
|
||||
"slug": area.slug,
|
||||
"description": area.description,
|
||||
}
|
||||
for area in obj.areas.all()
|
||||
]
|
||||
return []
|
||||
|
||||
# Metadata
|
||||
created_at = serializers.DateTimeField()
|
||||
updated_at = serializers.DateTimeField()
|
||||
|
||||
|
||||
class ParkCreateInputSerializer(serializers.Serializer):
|
||||
"""Input serializer for creating parks."""
|
||||
|
||||
name = serializers.CharField(max_length=255)
|
||||
description = serializers.CharField(allow_blank=True, default="")
|
||||
status = serializers.ChoiceField(
|
||||
choices=ModelChoices.get_park_status_choices(), default="OPERATING"
|
||||
)
|
||||
|
||||
# Optional details
|
||||
opening_date = serializers.DateField(required=False, allow_null=True)
|
||||
closing_date = serializers.DateField(required=False, allow_null=True)
|
||||
operating_season = serializers.CharField(
|
||||
max_length=255, required=False, allow_blank=True
|
||||
)
|
||||
size_acres = serializers.DecimalField(
|
||||
max_digits=10, decimal_places=2, required=False, allow_null=True
|
||||
)
|
||||
website = serializers.URLField(required=False, allow_blank=True)
|
||||
|
||||
# Required operator
|
||||
operator_id = serializers.IntegerField()
|
||||
|
||||
# Optional property owner
|
||||
property_owner_id = serializers.IntegerField(required=False, allow_null=True)
|
||||
|
||||
def validate(self, attrs):
|
||||
"""Cross-field validation."""
|
||||
opening_date = attrs.get("opening_date")
|
||||
closing_date = attrs.get("closing_date")
|
||||
|
||||
if opening_date and closing_date and closing_date < opening_date:
|
||||
raise serializers.ValidationError(
|
||||
"Closing date cannot be before opening date"
|
||||
)
|
||||
|
||||
return attrs
|
||||
|
||||
|
||||
class ParkUpdateInputSerializer(serializers.Serializer):
|
||||
"""Input serializer for updating parks."""
|
||||
|
||||
name = serializers.CharField(max_length=255, required=False)
|
||||
description = serializers.CharField(allow_blank=True, required=False)
|
||||
status = serializers.ChoiceField(
|
||||
choices=ModelChoices.get_park_status_choices(), required=False
|
||||
)
|
||||
|
||||
# Optional details
|
||||
opening_date = serializers.DateField(required=False, allow_null=True)
|
||||
closing_date = serializers.DateField(required=False, allow_null=True)
|
||||
operating_season = serializers.CharField(
|
||||
max_length=255, required=False, allow_blank=True
|
||||
)
|
||||
size_acres = serializers.DecimalField(
|
||||
max_digits=10, decimal_places=2, required=False, allow_null=True
|
||||
)
|
||||
website = serializers.URLField(required=False, allow_blank=True)
|
||||
|
||||
# Companies
|
||||
operator_id = serializers.IntegerField(required=False)
|
||||
property_owner_id = serializers.IntegerField(required=False, allow_null=True)
|
||||
|
||||
def validate(self, attrs):
|
||||
"""Cross-field validation."""
|
||||
opening_date = attrs.get("opening_date")
|
||||
closing_date = attrs.get("closing_date")
|
||||
|
||||
if opening_date and closing_date and closing_date < opening_date:
|
||||
raise serializers.ValidationError(
|
||||
"Closing date cannot be before opening date"
|
||||
)
|
||||
|
||||
return attrs
|
||||
|
||||
|
||||
class ParkFilterInputSerializer(serializers.Serializer):
|
||||
"""Input serializer for park filtering and search."""
|
||||
|
||||
# Search
|
||||
search = serializers.CharField(required=False, allow_blank=True)
|
||||
|
||||
# Status filter
|
||||
status = serializers.MultipleChoiceField(
|
||||
choices=[], required=False # Choices set dynamically
|
||||
)
|
||||
|
||||
# Location filters
|
||||
country = serializers.CharField(required=False, allow_blank=True)
|
||||
state = serializers.CharField(required=False, allow_blank=True)
|
||||
city = serializers.CharField(required=False, allow_blank=True)
|
||||
|
||||
# Rating filter
|
||||
min_rating = serializers.DecimalField(
|
||||
max_digits=3,
|
||||
decimal_places=2,
|
||||
required=False,
|
||||
min_value=1,
|
||||
max_value=10,
|
||||
)
|
||||
|
||||
# Size filter
|
||||
min_size_acres = serializers.DecimalField(
|
||||
max_digits=10, decimal_places=2, required=False, min_value=0
|
||||
)
|
||||
max_size_acres = serializers.DecimalField(
|
||||
max_digits=10, decimal_places=2, required=False, min_value=0
|
||||
)
|
||||
|
||||
# Company filters
|
||||
operator_id = serializers.IntegerField(required=False)
|
||||
property_owner_id = serializers.IntegerField(required=False)
|
||||
|
||||
# Ordering
|
||||
ordering = serializers.ChoiceField(
|
||||
choices=[
|
||||
"name",
|
||||
"-name",
|
||||
"opening_date",
|
||||
"-opening_date",
|
||||
"average_rating",
|
||||
"-average_rating",
|
||||
"coaster_count",
|
||||
"-coaster_count",
|
||||
"created_at",
|
||||
"-created_at",
|
||||
],
|
||||
required=False,
|
||||
default="name",
|
||||
)
|
||||
|
||||
|
||||
# === PARK AREA SERIALIZERS ===
|
||||
|
||||
|
||||
@extend_schema_serializer(
|
||||
examples=[
|
||||
OpenApiExample(
|
||||
"Park Area Example",
|
||||
summary="Example park area response",
|
||||
description="A themed area within a park",
|
||||
value={
|
||||
"id": 1,
|
||||
"name": "Tomorrowland",
|
||||
"slug": "tomorrowland",
|
||||
"description": "A futuristic themed area",
|
||||
"park": {"id": 1, "name": "Magic Kingdom", "slug": "magic-kingdom"},
|
||||
"opening_date": "1971-10-01",
|
||||
"closing_date": None,
|
||||
},
|
||||
)
|
||||
]
|
||||
)
|
||||
class ParkAreaDetailOutputSerializer(serializers.Serializer):
|
||||
"""Output serializer for park areas."""
|
||||
|
||||
id = serializers.IntegerField()
|
||||
name = serializers.CharField()
|
||||
slug = serializers.CharField()
|
||||
description = serializers.CharField()
|
||||
opening_date = serializers.DateField(allow_null=True)
|
||||
closing_date = serializers.DateField(allow_null=True)
|
||||
|
||||
# Park info
|
||||
park = serializers.SerializerMethodField()
|
||||
|
||||
@extend_schema_field(serializers.DictField())
|
||||
def get_park(self, obj) -> dict:
|
||||
return {
|
||||
"id": obj.park.id,
|
||||
"name": obj.park.name,
|
||||
"slug": obj.park.slug,
|
||||
}
|
||||
|
||||
|
||||
class ParkAreaCreateInputSerializer(serializers.Serializer):
|
||||
"""Input serializer for creating park areas."""
|
||||
|
||||
name = serializers.CharField(max_length=255)
|
||||
description = serializers.CharField(allow_blank=True, default="")
|
||||
park_id = serializers.IntegerField()
|
||||
opening_date = serializers.DateField(required=False, allow_null=True)
|
||||
closing_date = serializers.DateField(required=False, allow_null=True)
|
||||
|
||||
def validate(self, attrs):
|
||||
"""Cross-field validation."""
|
||||
opening_date = attrs.get("opening_date")
|
||||
closing_date = attrs.get("closing_date")
|
||||
|
||||
if opening_date and closing_date and closing_date < opening_date:
|
||||
raise serializers.ValidationError(
|
||||
"Closing date cannot be before opening date"
|
||||
)
|
||||
|
||||
return attrs
|
||||
|
||||
|
||||
class ParkAreaUpdateInputSerializer(serializers.Serializer):
|
||||
"""Input serializer for updating park areas."""
|
||||
|
||||
name = serializers.CharField(max_length=255, required=False)
|
||||
description = serializers.CharField(allow_blank=True, required=False)
|
||||
opening_date = serializers.DateField(required=False, allow_null=True)
|
||||
closing_date = serializers.DateField(required=False, allow_null=True)
|
||||
|
||||
def validate(self, attrs):
|
||||
"""Cross-field validation."""
|
||||
opening_date = attrs.get("opening_date")
|
||||
closing_date = attrs.get("closing_date")
|
||||
|
||||
if opening_date and closing_date and closing_date < opening_date:
|
||||
raise serializers.ValidationError(
|
||||
"Closing date cannot be before opening date"
|
||||
)
|
||||
|
||||
return attrs
|
||||
|
||||
|
||||
# === PARK LOCATION SERIALIZERS ===
|
||||
|
||||
|
||||
class ParkLocationOutputSerializer(serializers.Serializer):
|
||||
"""Output serializer for park locations."""
|
||||
|
||||
id = serializers.IntegerField()
|
||||
latitude = serializers.FloatField(allow_null=True)
|
||||
longitude = serializers.FloatField(allow_null=True)
|
||||
address = serializers.CharField()
|
||||
city = serializers.CharField()
|
||||
state = serializers.CharField()
|
||||
country = serializers.CharField()
|
||||
postal_code = serializers.CharField()
|
||||
formatted_address = serializers.CharField()
|
||||
|
||||
# Park info
|
||||
park = serializers.SerializerMethodField()
|
||||
|
||||
@extend_schema_field(serializers.DictField())
|
||||
def get_park(self, obj) -> dict:
|
||||
return {
|
||||
"id": obj.park.id,
|
||||
"name": obj.park.name,
|
||||
"slug": obj.park.slug,
|
||||
}
|
||||
|
||||
|
||||
class ParkLocationCreateInputSerializer(serializers.Serializer):
|
||||
"""Input serializer for creating park locations."""
|
||||
|
||||
park_id = serializers.IntegerField()
|
||||
latitude = serializers.FloatField(required=False, allow_null=True)
|
||||
longitude = serializers.FloatField(required=False, allow_null=True)
|
||||
address = serializers.CharField(max_length=255, allow_blank=True, default="")
|
||||
city = serializers.CharField(max_length=100)
|
||||
state = serializers.CharField(max_length=100)
|
||||
country = serializers.CharField(max_length=100)
|
||||
postal_code = serializers.CharField(max_length=20, allow_blank=True, default="")
|
||||
|
||||
|
||||
class ParkLocationUpdateInputSerializer(serializers.Serializer):
|
||||
"""Input serializer for updating park locations."""
|
||||
|
||||
latitude = serializers.FloatField(required=False, allow_null=True)
|
||||
longitude = serializers.FloatField(required=False, allow_null=True)
|
||||
address = serializers.CharField(max_length=255, allow_blank=True, required=False)
|
||||
city = serializers.CharField(max_length=100, required=False)
|
||||
state = serializers.CharField(max_length=100, required=False)
|
||||
country = serializers.CharField(max_length=100, required=False)
|
||||
postal_code = serializers.CharField(max_length=20, allow_blank=True, required=False)
|
||||
|
||||
|
||||
# === PARKS SEARCH SERIALIZERS ===
|
||||
|
||||
|
||||
class ParkSuggestionSerializer(serializers.Serializer):
|
||||
"""Serializer for park search suggestions."""
|
||||
|
||||
id = serializers.IntegerField()
|
||||
name = serializers.CharField()
|
||||
slug = serializers.CharField()
|
||||
location = serializers.CharField()
|
||||
status = serializers.CharField()
|
||||
coaster_count = serializers.IntegerField()
|
||||
|
||||
|
||||
class ParkSuggestionOutputSerializer(serializers.Serializer):
|
||||
"""Output serializer for park suggestions."""
|
||||
|
||||
results = ParkSuggestionSerializer(many=True)
|
||||
query = serializers.CharField()
|
||||
count = serializers.IntegerField()
|
||||
Reference in New Issue
Block a user