feat: Implement initial schema and add various API, service, and management command enhancements across the application.

This commit is contained in:
pacnpal
2026-01-01 15:13:01 -05:00
parent c95f99ca10
commit b243b17af7
413 changed files with 11164 additions and 17433 deletions

View File

@@ -50,18 +50,14 @@ from apps.parks.models import Park, ParkPhoto
class ParkPhotoOutputSerializer(serializers.ModelSerializer):
"""Enhanced output serializer for park photos with Cloudflare Images support."""
uploaded_by_username = serializers.CharField(
source="uploaded_by.username", read_only=True
)
uploaded_by_username = serializers.CharField(source="uploaded_by.username", read_only=True)
file_size = serializers.SerializerMethodField()
dimensions = serializers.SerializerMethodField()
image_url = serializers.SerializerMethodField()
image_variants = serializers.SerializerMethodField()
@extend_schema_field(
serializers.IntegerField(allow_null=True, help_text="File size in bytes")
)
@extend_schema_field(serializers.IntegerField(allow_null=True, help_text="File size in bytes"))
def get_file_size(self, obj):
"""Get file size in bytes."""
return obj.file_size
@@ -79,11 +75,7 @@ class ParkPhotoOutputSerializer(serializers.ModelSerializer):
"""Get image dimensions as [width, height]."""
return obj.dimensions
@extend_schema_field(
serializers.URLField(
help_text="Full URL to the Cloudflare Images asset", allow_null=True
)
)
@extend_schema_field(serializers.URLField(help_text="Full URL to the Cloudflare Images asset", allow_null=True))
def get_image_url(self, obj):
"""Get the full Cloudflare Images URL."""
if obj.image:
@@ -175,9 +167,7 @@ class ParkPhotoUpdateInputSerializer(serializers.ModelSerializer):
class ParkPhotoListOutputSerializer(serializers.ModelSerializer):
"""Optimized output serializer for park photo lists."""
uploaded_by_username = serializers.CharField(
source="uploaded_by.username", read_only=True
)
uploaded_by_username = serializers.CharField(source="uploaded_by.username", read_only=True)
class Meta:
model = ParkPhoto
@@ -196,12 +186,8 @@ class ParkPhotoListOutputSerializer(serializers.ModelSerializer):
class ParkPhotoApprovalInputSerializer(serializers.Serializer):
"""Input serializer for bulk photo approval operations."""
photo_ids = serializers.ListField(
child=serializers.IntegerField(), help_text="List of photo IDs to approve"
)
approve = serializers.BooleanField(
default=True, help_text="Whether to approve (True) or reject (False) the photos"
)
photo_ids = serializers.ListField(child=serializers.IntegerField(), help_text="List of photo IDs to approve")
approve = serializers.BooleanField(default=True, help_text="Whether to approve (True) or reject (False) the photos")
class ParkPhotoStatsOutputSerializer(serializers.Serializer):
@@ -261,7 +247,7 @@ class HybridParkSerializer(serializers.ModelSerializer):
def get_city(self, obj):
"""Get city from related location."""
try:
return obj.location.city if hasattr(obj, 'location') and obj.location else None
return obj.location.city if hasattr(obj, "location") and obj.location else None
except AttributeError:
return None
@@ -269,7 +255,7 @@ class HybridParkSerializer(serializers.ModelSerializer):
def get_state(self, obj):
"""Get state from related location."""
try:
return obj.location.state if hasattr(obj, 'location') and obj.location else None
return obj.location.state if hasattr(obj, "location") and obj.location else None
except AttributeError:
return None
@@ -277,7 +263,7 @@ class HybridParkSerializer(serializers.ModelSerializer):
def get_country(self, obj):
"""Get country from related location."""
try:
return obj.location.country if hasattr(obj, 'location') and obj.location else None
return obj.location.country if hasattr(obj, "location") and obj.location else None
except AttributeError:
return None
@@ -285,7 +271,7 @@ class HybridParkSerializer(serializers.ModelSerializer):
def get_continent(self, obj):
"""Get continent from related location."""
try:
return obj.location.continent if hasattr(obj, 'location') and obj.location else None
return obj.location.continent if hasattr(obj, "location") and obj.location else None
except AttributeError:
return None
@@ -293,7 +279,7 @@ class HybridParkSerializer(serializers.ModelSerializer):
def get_latitude(self, obj):
"""Get latitude from related location."""
try:
if hasattr(obj, 'location') and obj.location and obj.location.coordinates:
if hasattr(obj, "location") and obj.location and obj.location.coordinates:
return obj.location.coordinates[1] # PostGIS returns [lon, lat]
return None
except (AttributeError, IndexError, TypeError):
@@ -303,7 +289,7 @@ class HybridParkSerializer(serializers.ModelSerializer):
def get_longitude(self, obj):
"""Get longitude from related location."""
try:
if hasattr(obj, 'location') and obj.location and obj.location.coordinates:
if hasattr(obj, "location") and obj.location and obj.location.coordinates:
return obj.location.coordinates[0] # PostGIS returns [lon, lat]
return None
except (AttributeError, IndexError, TypeError):
@@ -333,13 +319,11 @@ class HybridParkSerializer(serializers.ModelSerializer):
"description",
"status",
"park_type",
# Dates and computed fields
"opening_date",
"closing_date",
"opening_year",
"operating_season",
# Location fields
"city",
"state",
@@ -347,28 +331,22 @@ class HybridParkSerializer(serializers.ModelSerializer):
"continent",
"latitude",
"longitude",
# Company relationships
"operator_name",
"property_owner_name",
# Statistics
"size_acres",
"average_rating",
"ride_count",
"coaster_count",
# Images
"banner_image_url",
"card_image_url",
# URLs
"website",
"url",
# Computed fields for filtering
"search_text",
# Metadata
"created_at",
"updated_at",