Add management command to seed comprehensive sample data for ThrillWiki application

- Implemented cleanup of existing sample data to avoid conflicts.
- Created functions to generate companies, parks, rides, park areas, and reviews.
- Ensured proper relationships between models during data creation.
- Added logging for better tracking of data seeding process.
- Included checks for required database tables before seeding.
This commit is contained in:
pacnpal
2025-08-20 10:16:21 -04:00
parent 641fc1a253
commit 78248aa892
11 changed files with 1489 additions and 64 deletions

2
.gitignore vendored
View File

@@ -388,3 +388,5 @@ Temporary Items
.github-token .github-token
logs/ logs/
profiles profiles
.thrillwiki-github-token
.thrillwiki-template-config

View File

@@ -0,0 +1,317 @@
from django.core.management.base import BaseCommand
from django.utils import timezone
from django.db import transaction
from datetime import date, timedelta
import random
from decimal import Decimal
# Import models from both apps
from parks.models import Company as ParkCompany, Park, ParkArea, ParkReview
from parks.models.location import ParkLocation
from rides.models import Company as RideCompany, Ride, RideModel, RideReview, RollerCoasterStats
from accounts.models import User
class Command(BaseCommand):
help = 'Creates comprehensive sample data for the ThrillWiki theme park application'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.created_companies = {}
self.created_parks = {}
self.created_rides = {}
def handle(self, *args, **options):
self.stdout.write('Starting sample data creation...')
try:
with transaction.atomic():
self.create_companies()
self.create_parks()
self.create_ride_models()
self.create_rides()
self.create_park_areas()
self.create_reviews()
self.stdout.write(self.style.SUCCESS('Successfully created comprehensive sample data!'))
self.print_summary()
except Exception as e:
self.stdout.write(self.style.ERROR(f'Error creating sample data: {e}'))
raise
def create_companies(self):
"""Create companies with different roles following entity relationship rules"""
self.stdout.write('Creating companies...')
# Park operators and property owners (using parks.models.Company)
park_operators_data = [
{
'name': 'The Walt Disney Company',
'slug': 'walt-disney-company',
'roles': ['OPERATOR', 'PROPERTY_OWNER'],
'description': 'World\'s largest entertainment company and theme park operator.',
'website': 'https://www.disney.com/',
'founded_year': 1923,
},
{
'name': 'Universal Parks & Resorts',
'slug': 'universal-parks-resorts',
'roles': ['OPERATOR', 'PROPERTY_OWNER'],
'description': 'Division of Comcast NBCUniversal, operating major theme parks worldwide.',
'website': 'https://www.universalparks.com/',
'founded_year': 1964,
},
{
'name': 'Six Flags Entertainment Corporation',
'slug': 'six-flags-entertainment',
'roles': ['OPERATOR', 'PROPERTY_OWNER'],
'description': 'World\'s largest regional theme park company.',
'website': 'https://www.sixflags.com/',
'founded_year': 1961,
},
{
'name': 'Cedar Fair Entertainment Company',
'slug': 'cedar-fair-entertainment',
'roles': ['OPERATOR', 'PROPERTY_OWNER'],
'description': 'One of North America\'s largest operators of regional amusement parks.',
'website': 'https://www.cedarfair.com/',
'founded_year': 1983,
},
{
'name': 'Herschend Family Entertainment',
'slug': 'herschend-family-entertainment',
'roles': ['OPERATOR', 'PROPERTY_OWNER'],
'description': 'Largest family-owned themed attractions corporation in the United States.',
'website': 'https://www.hfecorp.com/',
'founded_year': 1950,
},
{
'name': 'SeaWorld Parks & Entertainment',
'slug': 'seaworld-parks-entertainment',
'roles': ['OPERATOR', 'PROPERTY_OWNER'],
'description': 'Theme park and entertainment company focusing on nature-based themes.',
'website': 'https://www.seaworldentertainment.com/',
'founded_year': 1959,
},
{
'name': 'Merlin Entertainments',
'slug': 'merlin-entertainments',
'roles': ['OPERATOR', 'PROPERTY_OWNER'],
'description': 'European theme park operator with LEGOLAND and Madame Tussauds brands.',
'website': 'https://www.merlinentertainments.com/',
'founded_year': 1998,
},
]
for company_data in park_operators_data:
company, created = ParkCompany.objects.get_or_create(
slug=company_data['slug'],
defaults=company_data
)
self.created_companies[company.slug] = company
self.stdout.write(f' {"Created" if created else "Found"} park company: {company.name}')
# Ride manufacturers and designers (using rides.models.Company)
ride_companies_data = [
{
'name': 'Bolliger & Mabillard',
'slug': 'bolliger-mabillard',
'roles': ['MANUFACTURER', 'DESIGNER'],
'description': 'Swiss roller coaster manufacturer known for inverted and diving coasters.',
'website': 'https://www.bolliger-mabillard.com/',
'founded_date': '1988-01-01',
},
{
'name': 'Intamin Amusement Rides',
'slug': 'intamin-amusement-rides',
'roles': ['MANUFACTURER', 'DESIGNER'],
'description': 'Liechtenstein-based manufacturer of roller coasters and thrill rides.',
'website': 'https://www.intamin.com/',
'founded_date': '1967-01-01',
},
{
'name': 'Arrow Dynamics',
'slug': 'arrow-dynamics',
'roles': ['MANUFACTURER', 'DESIGNER'],
'description': 'American manufacturer known for corkscrew coasters and mine trains.',
'website': 'https://en.wikipedia.org/wiki/Arrow_Dynamics',
'founded_date': '1946-01-01',
},
{
'name': 'Vekoma Rides Manufacturing',
'slug': 'vekoma-rides-manufacturing',
'roles': ['MANUFACTURER', 'DESIGNER'],
'description': 'Dutch manufacturer of roller coasters and family rides.',
'website': 'https://www.vekoma.com/',
'founded_date': '1926-01-01',
},
{
'name': 'Rocky Mountain Construction',
'slug': 'rocky-mountain-construction',
'roles': ['MANUFACTURER', 'DESIGNER'],
'description': 'American manufacturer specializing in I-Box track and Raptor track coasters.',
'website': 'https://www.rockymtnconstruction.com/',
'founded_date': '2001-01-01',
},
{
'name': 'Mack Rides',
'slug': 'mack-rides',
'roles': ['MANUFACTURER', 'DESIGNER'],
'description': 'German manufacturer known for water rides and powered coasters.',
'website': 'https://www.mack-rides.com/',
'founded_date': '1780-01-01',
},
{
'name': 'Chance Rides',
'slug': 'chance-rides',
'roles': ['MANUFACTURER'],
'description': 'American manufacturer of thrill rides and amusement park equipment.',
'website': 'https://www.chancerides.com/',
'founded_date': '1961-01-01',
},
{
'name': 'S&S Worldwide',
'slug': 's-s-worldwide',
'roles': ['MANUFACTURER', 'DESIGNER'],
'description': 'American manufacturer known for drop towers and 4D free-fly coasters.',
'website': 'https://www.s-s.com/',
'founded_date': '1990-01-01',
},
{
'name': 'Zierer Rides',
'slug': 'zierer-rides',
'roles': ['MANUFACTURER'],
'description': 'German manufacturer of kiddie rides and family coasters.',
'website': 'https://www.zierer.com/',
'founded_date': '1950-01-01',
},
{
'name': 'Gerstlauer',
'slug': 'gerstlauer',
'roles': ['MANUFACTURER', 'DESIGNER'],
'description': 'German manufacturer known for Euro-Fighter and spinning coasters.',
'website': 'https://www.gerstlauer-rides.de/',
'founded_date': '1982-01-01',
},
]
for company_data in ride_companies_data:
company, created = RideCompany.objects.get_or_create(
slug=company_data['slug'],
defaults=company_data
)
self.created_companies[company.slug] = company
self.stdout.write(f' {"Created" if created else "Found"} ride company: {company.name}')
def create_parks(self):
"""Create parks with proper operator relationships"""
self.stdout.write('Creating parks...')
parks_data = [
{
'name': 'Magic Kingdom',
'slug': 'magic-kingdom',
'operator_slug': 'walt-disney-company',
'property_owner_slug': 'walt-disney-company',
'description': 'The first theme park at Walt Disney World Resort in Florida, opened in 1971.',
'opening_date': '1971-10-01',
'size_acres': 142,
'website': 'https://disneyworld.disney.go.com/destinations/magic-kingdom/',
'location': {
'street_address': '1180 Seven Seas Dr',
'city': 'Lake Buena Vista',
'state_province': 'Florida',
'country': 'USA',
'postal_code': '32830',
'latitude': 28.4177,
'longitude': -81.5812
}
},
{
'name': 'Universal Studios Florida',
'slug': 'universal-studios-florida',
'operator_slug': 'universal-parks-resorts',
'property_owner_slug': 'universal-parks-resorts',
'description': 'Movie and television-based theme park in Orlando, Florida.',
'opening_date': '1990-06-07',
'size_acres': 108,
'website': 'https://www.universalorlando.com/web/en/us/theme-parks/universal-studios-florida',
'location': {
'street_address': '6000 Universal Blvd',
'city': 'Orlando',
'state_province': 'Florida',
'country': 'USA',
'postal_code': '32819',
'latitude': 28.4749,
'longitude': -81.4687
}
},
{
'name': 'Cedar Point',
'slug': 'cedar-point',
'operator_slug': 'cedar-fair-entertainment',
'property_owner_slug': 'cedar-fair-entertainment',
'description': 'Known as the "Roller Coaster Capital of the World".',
'opening_date': '1870-06-01',
'size_acres': 364,
'website': 'https://www.cedarpoint.com/',
'location': {
'street_address': '1 Cedar Point Dr',
'city': 'Sandusky',
'state_province': 'Ohio',
'country': 'USA',
'postal_code': '44870',
'latitude': 41.4822,
'longitude': -82.6835
}
},
{
'name': 'Six Flags Magic Mountain',
'slug': 'six-flags-magic-mountain',
'operator_slug': 'six-flags-entertainment',
'property_owner_slug': 'six-flags-entertainment',
'description': 'Known for its world-record 19 roller coasters.',
'opening_date': '1971-05-29',
'size_acres': 262,
'website': 'https://www.sixflags.com/magicmountain',
'location': {
'street_address': '26101 Magic Mountain Pkwy',
'city': 'Valencia',
'state_province': 'California',
'country': 'USA',
'postal_code': '91355',
'latitude': 34.4253,
'longitude': -118.5971
}
},
{
'name': 'Europa-Park',
'slug': 'europa-park',
'operator_slug': 'merlin-entertainments',
'property_owner_slug': 'merlin-entertainments',
'description': 'One of the most popular theme parks in Europe, located in Germany.',
'opening_date': '1975-07-12',
'size_acres': 234,
'website': 'https://www.europapark.de/',
'location': {
'street_address': 'Europa-Park-Straße 2',
'city': 'Rust',
'state_province': 'Baden-Württemberg',
'country': 'Germany',
'postal_code': '77977',
'latitude': 48.2667,
'longitude': 7.7167
}
},
{
'name': 'Alton Towers',
'slug': 'alton-towers',
'operator_slug': 'merlin-entertainments',
'property_owner_slug': 'merlin-entertainments',
'description': 'Major theme park and former country estate in Staffordshire, England.',
'opening_date': '1980-04-23',
'size_acres': 500,
# Add other fields as needed
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,10 @@
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from django.db import models from django.db import models
from django.utils.text import slugify
from core.models import TrackedModel from core.models import TrackedModel
import pghistory import pghistory
@pghistory.track() @pghistory.track()
class Company(TrackedModel): class Company(TrackedModel):
@@ -10,6 +12,7 @@ class Company(TrackedModel):
from ..managers import CompanyManager from ..managers import CompanyManager
objects = CompanyManager() objects = CompanyManager()
class CompanyRole(models.TextChoices): class CompanyRole(models.TextChoices):
OPERATOR = 'OPERATOR', 'Park Operator' OPERATOR = 'OPERATOR', 'Park Operator'
PROPERTY_OWNER = 'PROPERTY_OWNER', 'Property Owner' PROPERTY_OWNER = 'PROPERTY_OWNER', 'Property Owner'
@@ -29,6 +32,11 @@ class Company(TrackedModel):
parks_count = models.IntegerField(default=0) parks_count = models.IntegerField(default=0)
rides_count = models.IntegerField(default=0) rides_count = models.IntegerField(default=0)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
super().save(*args, **kwargs)
def __str__(self): def __str__(self):
return self.name return self.name
@@ -36,6 +44,7 @@ class Company(TrackedModel):
ordering = ['name'] ordering = ['name']
verbose_name_plural = 'Companies' verbose_name_plural = 'Companies'
class CompanyHeadquarters(models.Model): class CompanyHeadquarters(models.Model):
""" """
Simple address storage for company headquarters without coordinate tracking. Simple address storage for company headquarters without coordinate tracking.

View File

@@ -33,12 +33,16 @@ urlpatterns = [
# Road trip planning URLs # Road trip planning URLs
path("roadtrip/", RoadTripPlannerView.as_view(), name="roadtrip_planner"), path("roadtrip/", RoadTripPlannerView.as_view(), name="roadtrip_planner"),
path("roadtrip/create/", CreateTripView.as_view(), name="roadtrip_create"), path("roadtrip/create/", CreateTripView.as_view(), name="roadtrip_create"),
path("roadtrip/<str:trip_id>/", TripDetailView.as_view(), name="roadtrip_detail"), path("roadtrip/<str:trip_id>/",
TripDetailView.as_view(), name="roadtrip_detail"),
# Road trip HTMX endpoints # Road trip HTMX endpoints
path("roadtrip/htmx/parks-along-route/", FindParksAlongRouteView.as_view(), name="roadtrip_htmx_parks_along_route"), path("roadtrip/htmx/parks-along-route/", FindParksAlongRouteView.as_view(),
path("roadtrip/htmx/geocode/", GeocodeAddressView.as_view(), name="roadtrip_htmx_geocode"), name="roadtrip_htmx_parks_along_route"),
path("roadtrip/htmx/distance/", ParkDistanceCalculatorView.as_view(), name="roadtrip_htmx_distance"), path("roadtrip/htmx/geocode/", GeocodeAddressView.as_view(),
name="roadtrip_htmx_geocode"),
path("roadtrip/htmx/distance/", ParkDistanceCalculatorView.as_view(),
name="roadtrip_htmx_distance"),
# Park detail and related views # Park detail and related views
path("<slug:slug>/", views.ParkDetailView.as_view(), name="park_detail"), path("<slug:slug>/", views.ParkDetailView.as_view(), name="park_detail"),
@@ -46,15 +50,22 @@ urlpatterns = [
path("<slug:slug>/actions/", views.park_actions, name="park_actions"), path("<slug:slug>/actions/", views.park_actions, name="park_actions"),
# Area views # Area views
path("<slug:park_slug>/areas/<slug:area_slug>/", views.ParkAreaDetailView.as_view(), name="area_detail"), path("<slug:park_slug>/areas/<slug:area_slug>/",
views.ParkAreaDetailView.as_view(), name="area_detail"),
# Park-specific category URLs # Park-specific category URLs
path("<slug:park_slug>/roller_coasters/", ParkSingleCategoryListView.as_view(), {'category': 'RC'}, name="park_roller_coasters"), path("<slug:park_slug>/roller_coasters/", ParkSingleCategoryListView.as_view(),
path("<slug:park_slug>/dark_rides/", ParkSingleCategoryListView.as_view(), {'category': 'DR'}, name="park_dark_rides"), {'category': 'RC'}, name="park_roller_coasters"),
path("<slug:park_slug>/flat_rides/", ParkSingleCategoryListView.as_view(), {'category': 'FR'}, name="park_flat_rides"), path("<slug:park_slug>/dark_rides/", ParkSingleCategoryListView.as_view(),
path("<slug:park_slug>/water_rides/", ParkSingleCategoryListView.as_view(), {'category': 'WR'}, name="park_water_rides"), {'category': 'DR'}, name="park_dark_rides"),
path("<slug:park_slug>/transports/", ParkSingleCategoryListView.as_view(), {'category': 'TR'}, name="park_transports"), path("<slug:park_slug>/flat_rides/", ParkSingleCategoryListView.as_view(),
path("<slug:park_slug>/others/", ParkSingleCategoryListView.as_view(), {'category': 'OT'}, name="park_others"), {'category': 'FR'}, name="park_flat_rides"),
path("<slug:park_slug>/water_rides/", ParkSingleCategoryListView.as_view(),
{'category': 'WR'}, name="park_water_rides"),
path("<slug:park_slug>/transports/", ParkSingleCategoryListView.as_view(),
{'category': 'TR'}, name="park_transports"),
path("<slug:park_slug>/others/", ParkSingleCategoryListView.as_view(),
{'category': 'OT'}, name="park_others"),
# Include park-specific rides URLs # Include park-specific rides URLs
path("<slug:park_slug>/rides/", include("rides.park_urls", namespace="rides")), path("<slug:park_slug>/rides/", include("rides.park_urls", namespace="rides")),

View File

@@ -312,6 +312,9 @@
.fixed { .fixed {
position: fixed; position: fixed;
} }
.fixed\! {
position: fixed !important;
}
.relative { .relative {
position: relative; position: relative;
} }
@@ -1575,9 +1578,6 @@
.text-yellow-800 { .text-yellow-800 {
color: var(--color-yellow-800); color: var(--color-yellow-800);
} }
.capitalize {
text-transform: capitalize;
}
.lowercase { .lowercase {
text-transform: lowercase; text-transform: lowercase;
} }

View File

@@ -63,8 +63,7 @@
<div class="text-center"> <div class="text-center">
<dt class="text-sm font-semibold text-gray-900 dark:text-white">Operator</dt> <dt class="text-sm font-semibold text-gray-900 dark:text-white">Operator</dt>
<dd class="mt-1"> <dd class="mt-1">
<a href="{% url 'operators:operator_detail' park.operator.slug %}" <span class="text-sm font-bold text-sky-900 dark:text-sky-400">
class="text-sm font-bold text-sky-900 dark:text-sky-400 hover:text-sky-800 dark:hover:text-sky-300">
{{ park.operator.name }} {{ park.operator.name }}
</a> </a>
</dd> </dd>

View File

@@ -41,10 +41,8 @@
{% endif %} {% endif %}
</div> </div>
{% if park.operator %} {% if park.operator %}
<div class="mt-4 text-sm text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"> <div class="mt-4 text-sm text-blue-600 dark:text-blue-400">
<a href="{% url 'operators:operator_detail' park.operator.slug %}"> {{ park.operator.name }}
{{ park.operator.name }}
</a>
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@@ -119,8 +119,7 @@
{% for operator in operators %} {% for operator in operators %}
<div class="p-4 rounded-lg bg-gray-50 dark:bg-gray-700"> <div class="p-4 rounded-lg bg-gray-50 dark:bg-gray-700">
<h3 class="mb-2 text-lg font-semibold"> <h3 class="mb-2 text-lg font-semibold">
<a href="{% url 'operators:operator_detail' operator.slug %}" <span class="text-blue-600 dark:text-blue-400">
class="text-blue-600 hover:underline dark:text-blue-400">
{{ operator.name }} {{ operator.name }}
</a> </a>
</h3> </h3>

View File

@@ -43,6 +43,8 @@ INSTALLED_APPS = [
"whitenoise", "whitenoise",
"django_tailwind_cli", "django_tailwind_cli",
"autocomplete", # Django HTMX Autocomplete "autocomplete", # Django HTMX Autocomplete
"debug_toolbar",
"silk",
"core", "core",
"accounts", "accounts",
"parks", "parks",
@@ -57,6 +59,7 @@ MIDDLEWARE = [
"django.middleware.cache.UpdateCacheMiddleware", "django.middleware.cache.UpdateCacheMiddleware",
"django.middleware.security.SecurityMiddleware", "django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware", "whitenoise.middleware.WhiteNoiseMiddleware",
"debug_toolbar.middleware.DebugToolbarMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware", "django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware", "django.middleware.csrf.CsrfViewMiddleware",
@@ -93,21 +96,19 @@ WSGI_APPLICATION = "thrillwiki.wsgi.application"
# Database # Database
# Parse database URL but force PostGIS engine # For development, use PostgreSQL with PostGIS for GeoDjango features
db_config = dj_database_url.config(
default="[DATABASE-URL-REMOVED]
conn_max_age=600,
conn_health_checks=True,
)
# Force PostGIS engine - override any parsed engine
DATABASES = { DATABASES = {
"default": { "default": {
**db_config,
"ENGINE": "django.contrib.gis.db.backends.postgis", "ENGINE": "django.contrib.gis.db.backends.postgis",
"NAME": "thrillwiki",
"USER": "postgres",
"PASSWORD": "postgres",
"HOST": "localhost",
"PORT": "5432",
} }
} }
# Cache settings # Cache settings
CACHES = { CACHES = {
"default": { "default": {
@@ -228,3 +229,9 @@ ROADTRIP_USER_AGENT = "ThrillWiki Road Trip Planner (https://thrillwiki.com)"
ROADTRIP_REQUEST_TIMEOUT = 10 # seconds ROADTRIP_REQUEST_TIMEOUT = 10 # seconds
ROADTRIP_MAX_RETRIES = 3 ROADTRIP_MAX_RETRIES = 3
ROADTRIP_BACKOFF_FACTOR = 2 ROADTRIP_BACKOFF_FACTOR = 2
# Debug Toolbar Configuration
INTERNAL_IPS = [
"127.0.0.1",
"localhost",
]

View File

@@ -32,25 +32,34 @@ urlpatterns = [
path("ac/", autocomplete_urls), path("ac/", autocomplete_urls),
# API Documentation URLs # API Documentation URLs
path("api/schema/", SpectacularAPIView.as_view(), name="schema") if HAS_SPECTACULAR else path("", lambda r: None), path("api/schema/", SpectacularAPIView.as_view(),
path("api/docs/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui") if HAS_SPECTACULAR else path("", lambda r: None), name="schema") if HAS_SPECTACULAR else path("", lambda r: None),
path("api/redoc/", SpectacularRedocView.as_view(url_name="schema"), name="redoc") if HAS_SPECTACULAR else path("", lambda r: None), path("api/docs/", SpectacularSwaggerView.as_view(url_name="schema"),
name="swagger-ui") if HAS_SPECTACULAR else path("", lambda r: None),
path("api/redoc/", SpectacularRedocView.as_view(url_name="schema"),
name="redoc") if HAS_SPECTACULAR else path("", lambda r: None),
# Health Check URLs # Health Check URLs
path("health/", include("health_check.urls")), path("health/", include("health_check.urls")),
path("health/api/", HealthCheckAPIView.as_view(), name="health-api") if HAS_HEALTH_VIEWS else path("", lambda r: None), path("health/api/", HealthCheckAPIView.as_view(),
path("health/simple/", SimpleHealthView.as_view(), name="health-simple") if HAS_HEALTH_VIEWS else path("", lambda r: None), name="health-api") if HAS_HEALTH_VIEWS else path("", lambda r: None),
path("health/metrics/", PerformanceMetricsView.as_view(), name="health-metrics") if HAS_HEALTH_VIEWS else path("", lambda r: None), path("health/simple/", SimpleHealthView.as_view(),
name="health-simple") if HAS_HEALTH_VIEWS else path("", lambda r: None),
path("health/metrics/", PerformanceMetricsView.as_view(),
name="health-metrics") if HAS_HEALTH_VIEWS else path("", lambda r: None),
# API URLs (before app URLs to avoid conflicts) # API URLs (before app URLs to avoid conflicts)
path("api/v1/", include("parks.api.urls", namespace="parks_api")), path("api/v1/", include("parks.api.urls", namespace="parks_api")),
path("api/v1/", include("rides.api.urls", namespace="rides_api")), path("api/v1/", include("rides.api.urls", namespace="rides_api")),
path("api/v1/map/", include("core.urls.map_urls", namespace="map_api")), # Map API URLs path("api/v1/map/", include("core.urls.map_urls",
namespace="map_api")), # Map API URLs
# Parks and Rides URLs # Parks and Rides URLs
path("parks/", include("parks.urls", namespace="parks")), path("parks/", include("parks.urls", namespace="parks")),
# Global rides URLs # Global rides URLs
path("rides/", include("rides.urls", namespace="rides")), path("rides/", include("rides.urls", namespace="rides")),
# Operators URLs
path("operators/", include("parks.urls", namespace="operators")),
# Other URLs # Other URLs
path("photos/", include("media.urls", namespace="photos")), # Add photos URLs path("photos/", include("media.urls", namespace="photos")), # Add photos URLs
path("search/", include("core.urls.search", namespace="search")), path("search/", include("core.urls.search", namespace="search")),
@@ -93,8 +102,10 @@ urlpatterns = [
# Serve static files in development # Serve static files in development
if settings.DEBUG: if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) urlpatterns += static(settings.STATIC_URL,
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
# Development monitoring URLs # Development monitoring URLs
try: try: