feat(rides): populate slugs for existing RideModel records and ensure uniqueness

- Added migration 0011 to populate unique slugs for existing RideModel records based on manufacturer and model names.
- Implemented logic to ensure slug uniqueness during population.
- Added reverse migration to clear slugs if needed.

feat(rides): enforce unique slugs for RideModel

- Created migration 0012 to alter the slug field in RideModel to be unique.
- Updated the slug field to include help text and a maximum length of 255 characters.

docs: integrate Cloudflare Images into rides and parks models

- Updated RidePhoto and ParkPhoto models to use CloudflareImagesField for image storage.
- Enhanced API serializers for rides and parks to support Cloudflare Images, including new fields for image URLs and variants.
- Provided comprehensive OpenAPI schema metadata for new fields.
- Documented database migrations for the integration.
- Detailed configuration settings for Cloudflare Images.
- Updated API response formats to include Cloudflare Images URLs and variants.
- Added examples for uploading photos via API and outlined testing procedures.
This commit is contained in:
pacnpal
2025-08-28 15:12:39 -04:00
parent 715e284b3e
commit 67db0aa46e
34 changed files with 6002 additions and 894 deletions

View File

@@ -16,7 +16,7 @@ from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import AllowAny
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter, OpenApiExample
from drf_spectacular.types import OpenApiTypes
from apps.parks.models import Park, ParkLocation
@@ -43,7 +43,7 @@ logger = logging.getLogger(__name__)
location=OpenApiParameter.QUERY,
required=False,
description="Northern latitude bound (-90 to 90). Used with south, east, west to define geographic bounds.",
examples=[41.5],
examples=[OpenApiExample("Example", value=41.5)],
),
OpenApiParameter(
"south",
@@ -51,7 +51,7 @@ logger = logging.getLogger(__name__)
location=OpenApiParameter.QUERY,
required=False,
description="Southern latitude bound (-90 to 90). Must be less than north bound.",
examples=[41.4],
examples=[OpenApiExample("Example", value=41.4)],
),
OpenApiParameter(
"east",
@@ -59,7 +59,7 @@ logger = logging.getLogger(__name__)
location=OpenApiParameter.QUERY,
required=False,
description="Eastern longitude bound (-180 to 180). Must be greater than west bound.",
examples=[-82.6],
examples=[OpenApiExample("Example", value=-82.6)],
),
OpenApiParameter(
"west",
@@ -67,7 +67,7 @@ logger = logging.getLogger(__name__)
location=OpenApiParameter.QUERY,
required=False,
description="Western longitude bound (-180 to 180). Used with other bounds for geographic filtering.",
examples=[-82.8],
examples=[OpenApiExample("Example", value=-82.8)],
),
OpenApiParameter(
"zoom",
@@ -75,7 +75,7 @@ logger = logging.getLogger(__name__)
location=OpenApiParameter.QUERY,
required=False,
description="Map zoom level (1-20). Higher values show more detail. Used for clustering decisions.",
examples=[10],
examples=[OpenApiExample("Example", value=10)],
),
OpenApiParameter(
"types",
@@ -83,7 +83,11 @@ logger = logging.getLogger(__name__)
location=OpenApiParameter.QUERY,
required=False,
description="Comma-separated location types to include. Valid values: 'park', 'ride'. Default: 'park,ride'",
examples=["park,ride", "park", "ride"],
examples=[
OpenApiExample("All types", value="park,ride"),
OpenApiExample("Parks only", value="park"),
OpenApiExample("Rides only", value="ride")
],
),
OpenApiParameter(
"cluster",
@@ -91,7 +95,10 @@ logger = logging.getLogger(__name__)
location=OpenApiParameter.QUERY,
required=False,
description="Enable location clustering for high-density areas. Default: false",
examples=[True, False],
examples=[
OpenApiExample("Enable clustering", value=True),
OpenApiExample("Disable clustering", value=False)
],
),
OpenApiParameter(
"q",
@@ -99,7 +106,11 @@ logger = logging.getLogger(__name__)
location=OpenApiParameter.QUERY,
required=False,
description="Text search query. Searches park/ride names, cities, and states.",
examples=["Cedar Point", "roller coaster", "Ohio"],
examples=[
OpenApiExample("Park name", value="Cedar Point"),
OpenApiExample("Ride type", value="roller coaster"),
OpenApiExample("Location", value="Ohio")
],
),
],
responses={