mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 16:11:08 -05:00
- 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.
1073 lines
48 KiB
Python
1073 lines
48 KiB
Python
from django.core.management.base import BaseCommand
|
|
from django.utils import timezone
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from django.db import transaction, connection
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
from django.db import IntegrityError
|
|
from django.apps import apps
|
|
import logging
|
|
from decimal import Decimal
|
|
from datetime import date, timedelta
|
|
import random
|
|
|
|
from parks.models import Company, Park, ParkArea, ParkReview, ParkLocation
|
|
from rides.models import Company as RideCompany, Ride, RideModel, RideReview, RollerCoasterStats
|
|
from accounts.models import User
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = 'Seeds comprehensive sample data for the ThrillWiki theme park application'
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.logger = logging.getLogger(__name__)
|
|
|
|
def cleanup_existing_data(self):
|
|
"""Clean up all existing sample data before creating new data"""
|
|
self.stdout.write('Cleaning up existing sample data...')
|
|
|
|
try:
|
|
with transaction.atomic():
|
|
# Count existing data for logging
|
|
park_review_count = ParkReview.objects.count()
|
|
ride_review_count = RideReview.objects.count()
|
|
rollercoaster_stats_count = RollerCoasterStats.objects.count()
|
|
ride_count = Ride.objects.count()
|
|
ride_model_count = RideModel.objects.count()
|
|
park_area_count = ParkArea.objects.count()
|
|
park_location_count = ParkLocation.objects.count()
|
|
park_count = Park.objects.count()
|
|
ride_company_count = RideCompany.objects.count()
|
|
company_count = Company.objects.count()
|
|
test_user_count = User.objects.filter(
|
|
username='testuser').count()
|
|
|
|
# Log what will be deleted
|
|
self.stdout.write(
|
|
f' Found {park_review_count} park reviews to delete')
|
|
self.stdout.write(
|
|
f' Found {ride_review_count} ride reviews to delete')
|
|
self.stdout.write(
|
|
f' Found {rollercoaster_stats_count} roller coaster stats to delete')
|
|
self.stdout.write(f' Found {ride_count} rides to delete')
|
|
self.stdout.write(
|
|
f' Found {ride_model_count} ride models to delete')
|
|
self.stdout.write(
|
|
f' Found {park_area_count} park areas to delete')
|
|
self.stdout.write(
|
|
f' Found {park_location_count} park locations to delete')
|
|
self.stdout.write(f' Found {park_count} parks to delete')
|
|
self.stdout.write(
|
|
f' Found {ride_company_count} ride companies to delete')
|
|
self.stdout.write(
|
|
f' Found {company_count} park companies to delete')
|
|
self.stdout.write(
|
|
f' Found {test_user_count} test users to delete')
|
|
|
|
# Delete in order to avoid foreign key constraint violations
|
|
# Reviews first (they reference other objects)
|
|
if park_review_count > 0:
|
|
ParkReview.objects.all().delete()
|
|
self.stdout.write(
|
|
f' Deleted {park_review_count} park reviews')
|
|
|
|
if ride_review_count > 0:
|
|
RideReview.objects.all().delete()
|
|
self.stdout.write(
|
|
f' Deleted {ride_review_count} ride reviews')
|
|
|
|
# Roller coaster stats (references Ride)
|
|
if rollercoaster_stats_count > 0:
|
|
RollerCoasterStats.objects.all().delete()
|
|
self.stdout.write(
|
|
f' Deleted {rollercoaster_stats_count} roller coaster stats')
|
|
|
|
# Rides (references Park, RideCompany, RideModel)
|
|
if ride_count > 0:
|
|
Ride.objects.all().delete()
|
|
self.stdout.write(f' Deleted {ride_count} rides')
|
|
|
|
# Ride models (referenced by Ride)
|
|
if ride_model_count > 0:
|
|
RideModel.objects.all().delete()
|
|
self.stdout.write(
|
|
f' Deleted {ride_model_count} ride models')
|
|
|
|
# Park areas (references Park)
|
|
if park_area_count > 0:
|
|
ParkArea.objects.all().delete()
|
|
self.stdout.write(
|
|
f' Deleted {park_area_count} park areas')
|
|
|
|
# Park locations (references Park)
|
|
if park_location_count > 0:
|
|
ParkLocation.objects.all().delete()
|
|
self.stdout.write(
|
|
f' Deleted {park_location_count} park locations')
|
|
|
|
# Parks (referenced by many models)
|
|
if park_count > 0:
|
|
Park.objects.all().delete()
|
|
self.stdout.write(f' Deleted {park_count} parks')
|
|
|
|
# Ride companies (referenced by Ride, RideModel)
|
|
if ride_company_count > 0:
|
|
RideCompany.objects.all().delete()
|
|
self.stdout.write(
|
|
f' Deleted {ride_company_count} ride companies')
|
|
|
|
# Park companies (referenced by Park)
|
|
if company_count > 0:
|
|
Company.objects.all().delete()
|
|
self.stdout.write(
|
|
f' Deleted {company_count} park companies')
|
|
|
|
# Only delete test user, not all users
|
|
if test_user_count > 0:
|
|
User.objects.filter(username='testuser').delete()
|
|
self.stdout.write(
|
|
f' Deleted {test_user_count} test users')
|
|
|
|
self.stdout.write(self.style.SUCCESS(
|
|
'Successfully cleaned up existing sample data!'))
|
|
|
|
except Exception as e:
|
|
self.logger.error(
|
|
f'Error during data cleanup: {str(e)}', exc_info=True)
|
|
self.stdout.write(self.style.ERROR(
|
|
f'Failed to clean up existing data: {str(e)}'))
|
|
raise
|
|
|
|
def handle(self, *args, **options):
|
|
self.stdout.write('Starting sample data creation...')
|
|
|
|
try:
|
|
# Check if required tables exist
|
|
if not self.check_required_tables():
|
|
self.stdout.write(self.style.ERROR(
|
|
'Required database tables are missing. Please run migrations first.'))
|
|
return
|
|
|
|
# Clean up existing data first
|
|
self.cleanup_existing_data()
|
|
|
|
# Use transaction to ensure data consistency
|
|
with transaction.atomic():
|
|
# Create companies with different roles
|
|
self.create_companies()
|
|
|
|
# Create parks with proper operator relationships
|
|
self.create_parks()
|
|
|
|
# Create rides with manufacturer and designer relationships
|
|
self.create_rides()
|
|
|
|
# Add park areas for variety
|
|
self.create_park_areas()
|
|
|
|
# Add sample reviews for testing
|
|
self.create_reviews()
|
|
|
|
self.stdout.write(self.style.SUCCESS(
|
|
'Successfully created comprehensive sample data!'))
|
|
|
|
except Exception as e:
|
|
self.logger.error(
|
|
f'Error during sample data creation: {str(e)}', exc_info=True)
|
|
self.stdout.write(self.style.ERROR(
|
|
f'Failed to create sample data: {str(e)}'))
|
|
raise
|
|
|
|
def check_required_tables(self):
|
|
"""Check if all required tables exist in the database"""
|
|
required_models = [
|
|
Company, Park, ParkArea, ParkReview, ParkLocation,
|
|
RideCompany, Ride, RideModel, RideReview, RollerCoasterStats,
|
|
User
|
|
]
|
|
|
|
missing_tables = []
|
|
for model in required_models:
|
|
try:
|
|
# Check if the table exists by trying to get the table name
|
|
table_name = model._meta.db_table
|
|
with connection.cursor() as cursor:
|
|
cursor.execute(f"SELECT 1 FROM {table_name} LIMIT 1")
|
|
except Exception as e:
|
|
missing_tables.append(model._meta.label)
|
|
|
|
if missing_tables:
|
|
self.stdout.write(self.style.WARNING(
|
|
f'Missing tables for models: {", ".join(missing_tables)}'))
|
|
return False
|
|
|
|
self.stdout.write(self.style.SUCCESS('All required tables exist.'))
|
|
return True
|
|
|
|
def create_companies(self):
|
|
"""Create companies with different roles (operators, manufacturers, designers)"""
|
|
self.stdout.write('Creating companies...')
|
|
|
|
try:
|
|
# Park Operators
|
|
operators_data = [
|
|
{
|
|
'name': 'The Walt Disney Company',
|
|
'roles': ['OPERATOR'],
|
|
'website': 'https://www.disney.com/',
|
|
'description': 'World\'s largest entertainment company and theme park operator.',
|
|
'founded_year': 1923,
|
|
},
|
|
{
|
|
'name': 'Universal Parks & Resorts',
|
|
'roles': ['OPERATOR'],
|
|
'website': 'https://www.universalparks.com/',
|
|
'description': 'Division of Comcast NBCUniversal, operating major theme parks worldwide.',
|
|
'founded_year': 1964,
|
|
},
|
|
{
|
|
'name': 'Six Flags Entertainment Corporation',
|
|
'roles': ['OPERATOR'],
|
|
'website': 'https://www.sixflags.com/',
|
|
'description': 'World\'s largest regional theme park company.',
|
|
'founded_year': 1961,
|
|
},
|
|
{
|
|
'name': 'Cedar Fair Entertainment Company',
|
|
'roles': ['OPERATOR'],
|
|
'website': 'https://www.cedarfair.com/',
|
|
'description': 'One of North America\'s largest operators of regional amusement parks.',
|
|
'founded_year': 1983,
|
|
},
|
|
{
|
|
'name': 'Herschend Family Entertainment',
|
|
'roles': ['OPERATOR'],
|
|
'website': 'https://www.hfecorp.com/',
|
|
'description': 'Largest family-owned themed attractions corporation in the United States.',
|
|
'founded_year': 1950,
|
|
},
|
|
{
|
|
'name': 'Europa-Park GmbH & Co. Mack KG',
|
|
'roles': ['OPERATOR'],
|
|
'website': 'https://www.europapark.de/',
|
|
'description': 'One of Europe\'s largest theme parks, located in Germany.',
|
|
'founded_year': 1975,
|
|
},
|
|
]
|
|
|
|
# Ride Manufacturers
|
|
manufacturers_data = [
|
|
{
|
|
'name': 'Bolliger & Mabillard',
|
|
'roles': ['MANUFACTURER'],
|
|
'website': 'https://www.bolliger-mabillard.com/',
|
|
'description': 'Swiss roller coaster manufacturer known for inverted and hyper coasters.',
|
|
'founded_date': '1988-01-01',
|
|
},
|
|
{
|
|
'name': 'Intamin Amusement Rides',
|
|
'roles': ['MANUFACTURER'],
|
|
'website': 'https://www.intamin.com/',
|
|
'description': 'Liechtenstein-based manufacturer of roller coasters and thrill rides.',
|
|
'founded_date': '1967-01-01',
|
|
},
|
|
{
|
|
'name': 'Vekoma Rides Manufacturing',
|
|
'roles': ['MANUFACTURER'],
|
|
'website': 'https://www.vekoma.com/',
|
|
'description': 'Dutch manufacturer specializing in family and steel roller coasters.',
|
|
'founded_date': '1926-01-01',
|
|
},
|
|
{
|
|
'name': 'Arrow Dynamics',
|
|
'roles': ['MANUFACTURER'],
|
|
'website': 'https://www.arrowdynamics.com/',
|
|
'description': 'American manufacturer known for corkscrew and looping coasters.',
|
|
'founded_date': '1946-01-01',
|
|
},
|
|
{
|
|
'name': 'Rocky Mountain Construction',
|
|
'roles': ['MANUFACTURER'],
|
|
'website': 'https://www.rockymtnconstruction.com/',
|
|
'description': 'American manufacturer known for I-Box track and wooden coasters.',
|
|
'founded_date': '2001-01-01',
|
|
},
|
|
{
|
|
'name': 'Mack Rides GmbH & Co KG',
|
|
'roles': ['MANUFACTURER'],
|
|
'website': 'https://www.mack-rides.com/',
|
|
'description': 'German manufacturer of roller coasters and water rides.',
|
|
'founded_date': '1780-01-01',
|
|
},
|
|
]
|
|
|
|
# Ride Designers
|
|
designers_data = [
|
|
{
|
|
'name': 'Werner Stengel',
|
|
'roles': ['DESIGNER'],
|
|
'website': '',
|
|
'description': 'German roller coaster designer known for complex layouts and inversions.',
|
|
},
|
|
{
|
|
'name': 'Alan Schilke',
|
|
'roles': ['DESIGNER'],
|
|
'website': '',
|
|
'description': 'American roller coaster designer known for family-friendly coasters.',
|
|
},
|
|
{
|
|
'name': 'John Pierce',
|
|
'roles': ['DESIGNER'],
|
|
'website': '',
|
|
'description': 'American roller coaster designer and engineer.',
|
|
},
|
|
{
|
|
'name': 'The Gravity Group',
|
|
'roles': ['DESIGNER'],
|
|
'website': 'https://www.thegravitygroup.com/',
|
|
'description': 'American design firm specializing in roller coaster design.',
|
|
},
|
|
]
|
|
|
|
# Create companies in parks app (for operators and property owners)
|
|
self.park_companies = {}
|
|
for data in operators_data:
|
|
try:
|
|
company, created = Company.objects.get_or_create(
|
|
name=data['name'],
|
|
defaults={
|
|
'roles': data['roles'],
|
|
'website': data['website'],
|
|
'description': data['description'],
|
|
'founded_year': data['founded_year'],
|
|
}
|
|
)
|
|
self.park_companies[data['name']] = company
|
|
self.stdout.write(
|
|
f' {"Created" if created else "Found"} park company: {company.name}')
|
|
except Exception as e:
|
|
self.logger.error(
|
|
f'Error creating park company {data["name"]}: {str(e)}')
|
|
raise
|
|
|
|
# Create companies in rides app (for manufacturers and designers)
|
|
self.ride_companies = {}
|
|
for data in manufacturers_data + designers_data:
|
|
try:
|
|
company, created = RideCompany.objects.get_or_create(
|
|
name=data['name'],
|
|
defaults={
|
|
'roles': data['roles'],
|
|
'website': data['website'],
|
|
'description': data['description'],
|
|
'founded_date': data.get('founded_date'),
|
|
}
|
|
)
|
|
self.ride_companies[data['name']] = company
|
|
self.stdout.write(
|
|
f' {"Created" if created else "Found"} ride company: {company.name}')
|
|
except Exception as e:
|
|
self.logger.error(
|
|
f'Error creating ride company {data["name"]}: {str(e)}')
|
|
raise
|
|
|
|
except Exception as e:
|
|
self.logger.error(f'Error in create_companies: {str(e)}')
|
|
raise
|
|
|
|
def create_parks(self):
|
|
"""Create parks with proper operator relationships"""
|
|
self.stdout.write('Creating parks...')
|
|
|
|
try:
|
|
parks_data = [
|
|
{
|
|
'name': 'Magic Kingdom',
|
|
'operator': 'The Walt Disney Company',
|
|
'property_owner': 'The 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': 'Florida',
|
|
'country': 'United States',
|
|
'postal_code': '32830',
|
|
'latitude': 28.4177,
|
|
'longitude': -81.5812
|
|
}
|
|
},
|
|
{
|
|
'name': 'Universal Studios Florida',
|
|
'operator': 'Universal Parks & Resorts',
|
|
'property_owner': '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': 'Florida',
|
|
'country': 'United States',
|
|
'postal_code': '32819',
|
|
'latitude': 28.4749,
|
|
'longitude': -81.4687
|
|
}
|
|
},
|
|
{
|
|
'name': 'Cedar Point',
|
|
'operator': 'Cedar Fair Entertainment Company',
|
|
'property_owner': 'Cedar Fair Entertainment Company',
|
|
'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': 'Ohio',
|
|
'country': 'United States',
|
|
'postal_code': '44870',
|
|
'latitude': 41.4822,
|
|
'longitude': -82.6835
|
|
}
|
|
},
|
|
{
|
|
'name': 'Europa-Park',
|
|
'operator': 'Europa-Park GmbH & Co. Mack KG',
|
|
'property_owner': 'Europa-Park GmbH & Co. Mack KG',
|
|
'description': 'One of Europe\'s largest theme parks, located in Germany.',
|
|
'opening_date': '1975-07-12',
|
|
'size_acres': 235,
|
|
'website': 'https://www.europapark.de/',
|
|
'location': {
|
|
'street_address': 'Europa-Park-Straße 2',
|
|
'city': 'Rust',
|
|
'state': 'Baden-Württemberg',
|
|
'country': 'Germany',
|
|
'postal_code': '77977',
|
|
'latitude': 48.2667,
|
|
'longitude': 7.7167
|
|
}
|
|
},
|
|
{
|
|
'name': 'Six Flags Magic Mountain',
|
|
'operator': 'Six Flags Entertainment Corporation',
|
|
'property_owner': 'Six Flags Entertainment Corporation',
|
|
'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': 'California',
|
|
'country': 'United States',
|
|
'postal_code': '91355',
|
|
'latitude': 34.4253,
|
|
'longitude': -118.5971
|
|
}
|
|
},
|
|
{
|
|
'name': 'Silver Dollar City',
|
|
'operator': 'Herschend Family Entertainment',
|
|
'property_owner': 'Herschend Family Entertainment',
|
|
'description': 'An 1880s-themed park featuring over 40 rides and attractions.',
|
|
'opening_date': '1960-05-01',
|
|
'size_acres': 61,
|
|
'website': 'https://www.silverdollarcity.com/',
|
|
'location': {
|
|
'street_address': '399 Silver Dollar City Parkway',
|
|
'city': 'Branson',
|
|
'state': 'Missouri',
|
|
'country': 'United States',
|
|
'postal_code': '65616',
|
|
'latitude': 36.668497,
|
|
'longitude': -93.339074
|
|
}
|
|
},
|
|
]
|
|
|
|
self.parks = {}
|
|
for park_data in parks_data:
|
|
try:
|
|
operator = self.park_companies[park_data['operator']]
|
|
property_owner = self.park_companies.get(
|
|
park_data['property_owner']) if park_data['property_owner'] else None
|
|
|
|
park, created = Park.objects.get_or_create(
|
|
name=park_data['name'],
|
|
defaults={
|
|
'description': park_data['description'],
|
|
'status': 'OPERATING',
|
|
'opening_date': park_data['opening_date'],
|
|
'size_acres': park_data['size_acres'],
|
|
'website': park_data['website'],
|
|
'operator': operator,
|
|
'property_owner': property_owner,
|
|
}
|
|
)
|
|
self.parks[park_data['name']] = park
|
|
self.stdout.write(
|
|
f' {"Created" if created else "Found"} park: {park.name}')
|
|
|
|
# Create location for park
|
|
if created:
|
|
try:
|
|
loc_data = park_data['location']
|
|
park_location = ParkLocation.objects.create(
|
|
park=park,
|
|
street_address=loc_data['street_address'],
|
|
city=loc_data['city'],
|
|
state=loc_data['state'],
|
|
country=loc_data['country'],
|
|
postal_code=loc_data['postal_code']
|
|
)
|
|
# Set coordinates using the helper method
|
|
park_location.set_coordinates(
|
|
loc_data['latitude'],
|
|
loc_data['longitude']
|
|
)
|
|
park_location.save()
|
|
except Exception as e:
|
|
self.logger.error(
|
|
f'Error creating location for park {park_data["name"]}: {str(e)}')
|
|
raise
|
|
|
|
except Exception as e:
|
|
self.logger.error(
|
|
f'Error creating park {park_data["name"]}: {str(e)}')
|
|
raise
|
|
|
|
except Exception as e:
|
|
self.logger.error(f'Error in create_parks: {str(e)}')
|
|
raise
|
|
|
|
def create_rides(self):
|
|
"""Create rides with manufacturer and designer relationships"""
|
|
self.stdout.write('Creating rides...')
|
|
|
|
try:
|
|
# First create some ride models
|
|
ride_models_data = [
|
|
{
|
|
'name': 'Dive Coaster',
|
|
'manufacturer': 'Bolliger & Mabillard',
|
|
'category': 'RC',
|
|
'description': 'Inverted roller coaster with a vertical drop and non-inverting loop'
|
|
},
|
|
{
|
|
'name': 'Hyper Coaster',
|
|
'manufacturer': 'Bolliger & Mabillard',
|
|
'category': 'RC',
|
|
'description': 'Steel roller coaster with heights over 200 feet'
|
|
},
|
|
{
|
|
'name': 'Boomerang',
|
|
'manufacturer': 'Vekoma Rides Manufacturing',
|
|
'category': 'RC',
|
|
'description': 'Shuttle roller coaster that runs forward and backward'
|
|
},
|
|
{
|
|
'name': 'Corkscrew Coaster',
|
|
'manufacturer': 'Arrow Dynamics',
|
|
'category': 'RC',
|
|
'description': 'Early steel coaster design with corkscrew elements'
|
|
},
|
|
{
|
|
'name': 'I-Box Track',
|
|
'manufacturer': 'Rocky Mountain Construction',
|
|
'category': 'RC',
|
|
'description': 'Smooth-riding steel track system for wooden coasters'
|
|
},
|
|
{
|
|
'name': 'Powered Coaster',
|
|
'manufacturer': 'Mack Rides GmbH & Co KG',
|
|
'category': 'RC',
|
|
'description': 'Family-friendly steel roller coaster'
|
|
},
|
|
]
|
|
|
|
self.ride_models = {}
|
|
for model_data in ride_models_data:
|
|
try:
|
|
manufacturer = self.ride_companies.get(
|
|
model_data['manufacturer'])
|
|
model, created = RideModel.objects.get_or_create(
|
|
name=model_data['name'],
|
|
manufacturer=manufacturer,
|
|
defaults={
|
|
'description': model_data['description'],
|
|
'category': model_data['category'],
|
|
}
|
|
)
|
|
self.ride_models[model_data['name']] = model
|
|
self.stdout.write(
|
|
f' {"Created" if created else "Found"} ride model: {model.name}')
|
|
except Exception as e:
|
|
self.logger.error(
|
|
f'Error creating ride model {model_data["name"]}: {str(e)}')
|
|
raise
|
|
|
|
# Create rides
|
|
rides_data = [
|
|
{
|
|
'name': 'Millennium Force',
|
|
'park': 'Cedar Point',
|
|
'manufacturer': 'Bolliger & Mabillard',
|
|
'designer': 'Werner Stengel',
|
|
'ride_model': 'Hyper Coaster',
|
|
'category': 'RC',
|
|
'description': 'World\'s first hyper coaster reaching speeds of 93 mph.',
|
|
'opening_date': '2000-05-13',
|
|
'coaster_stats': {
|
|
'height_ft': 310,
|
|
'length_ft': 6595,
|
|
'speed_mph': 93,
|
|
'inversions': 0,
|
|
'ride_time_seconds': 165,
|
|
'track_material': 'STEEL',
|
|
'roller_coaster_type': 'SITDOWN',
|
|
'max_drop_height_ft': 300,
|
|
'launch_type': 'CHAIN',
|
|
'trains_count': 3,
|
|
'cars_per_train': 9,
|
|
'seats_per_car': 4,
|
|
}
|
|
},
|
|
{
|
|
'name': 'Top Thrill Dragster',
|
|
'park': 'Cedar Point',
|
|
'manufacturer': 'Intamin Amusement Rides',
|
|
'designer': 'Werner Stengel',
|
|
'category': 'RC',
|
|
'description': 'World\'s first strata coaster reaching 420 feet.',
|
|
'opening_date': '2003-05-04',
|
|
'coaster_stats': {
|
|
'height_ft': 420,
|
|
'length_ft': 2800,
|
|
'speed_mph': 120,
|
|
'inversions': 0,
|
|
'ride_time_seconds': 17,
|
|
'track_material': 'STEEL',
|
|
'roller_coaster_type': 'SITDOWN',
|
|
'max_drop_height_ft': 400,
|
|
'launch_type': 'HYDRAULIC',
|
|
'trains_count': 1,
|
|
'cars_per_train': 1,
|
|
'seats_per_car': 16,
|
|
}
|
|
},
|
|
{
|
|
'name': 'Silver Star',
|
|
'park': 'Europa-Park',
|
|
'manufacturer': 'Bolliger & Mabillard',
|
|
'designer': 'Werner Stengel',
|
|
'ride_model': 'Dive Coaster',
|
|
'category': 'RC',
|
|
'description': 'Europe\'s first dive coaster with a 300-foot drop.',
|
|
'opening_date': '2002-03-23',
|
|
'coaster_stats': {
|
|
'height_ft': 239,
|
|
'length_ft': 5249,
|
|
'speed_mph': 80,
|
|
'inversions': 0,
|
|
'ride_time_seconds': 240,
|
|
'track_material': 'STEEL',
|
|
'roller_coaster_type': 'SITDOWN',
|
|
'max_drop_height_ft': 197,
|
|
'launch_type': 'CHAIN',
|
|
'trains_count': 2,
|
|
'cars_per_train': 10,
|
|
'seats_per_car': 2,
|
|
}
|
|
},
|
|
{
|
|
'name': 'Blue Fire',
|
|
'park': 'Europa-Park',
|
|
'manufacturer': 'Mack Rides GmbH & Co KG',
|
|
'designer': 'John Pierce',
|
|
'ride_model': 'Powered Coaster',
|
|
'category': 'RC',
|
|
'description': 'Launched roller coaster with a 124-foot drop.',
|
|
'opening_date': '2009-04-25',
|
|
'coaster_stats': {
|
|
'height_ft': 124,
|
|
'length_ft': 2789,
|
|
'speed_mph': 62,
|
|
'inversions': 0,
|
|
'ride_time_seconds': 120,
|
|
'track_material': 'STEEL',
|
|
'roller_coaster_type': 'SITDOWN',
|
|
'max_drop_height_ft': 98,
|
|
'launch_type': 'HYDRAULIC',
|
|
'trains_count': 2,
|
|
'cars_per_train': 5,
|
|
'seats_per_car': 4,
|
|
}
|
|
},
|
|
{
|
|
'name': 'Space Mountain',
|
|
'park': 'Magic Kingdom',
|
|
'manufacturer': 'Arrow Dynamics',
|
|
'designer': 'John Pierce',
|
|
'category': 'RC',
|
|
'description': 'Indoor space-themed roller coaster.',
|
|
'opening_date': '1975-01-15',
|
|
'coaster_stats': {
|
|
'height_ft': 183,
|
|
'length_ft': 3200,
|
|
'speed_mph': 35,
|
|
'inversions': 0,
|
|
'ride_time_seconds': 180,
|
|
'track_material': 'STEEL',
|
|
'roller_coaster_type': 'SITDOWN',
|
|
'max_drop_height_ft': 150,
|
|
'launch_type': 'CHAIN',
|
|
'trains_count': 2,
|
|
'cars_per_train': 6,
|
|
'seats_per_car': 2,
|
|
}
|
|
},
|
|
{
|
|
'name': 'Big Thunder Mountain Railroad',
|
|
'park': 'Magic Kingdom',
|
|
'manufacturer': 'Arrow Dynamics',
|
|
'designer': 'The Gravity Group',
|
|
'category': 'RC',
|
|
'description': 'Mine train roller coaster themed as a runaway mining train.',
|
|
'opening_date': '1980-11-15',
|
|
'coaster_stats': {
|
|
'height_ft': 146,
|
|
'length_ft': 3280,
|
|
'speed_mph': 35,
|
|
'inversions': 0,
|
|
'ride_time_seconds': 240,
|
|
'track_material': 'STEEL',
|
|
'roller_coaster_type': 'SITDOWN',
|
|
'max_drop_height_ft': 128,
|
|
'launch_type': 'CHAIN',
|
|
'trains_count': 3,
|
|
'cars_per_train': 5,
|
|
'seats_per_car': 4,
|
|
}
|
|
},
|
|
{
|
|
'name': 'Maverick',
|
|
'park': 'Cedar Point',
|
|
'manufacturer': 'Intamin Amusement Rides',
|
|
'designer': 'Werner Stengel',
|
|
'category': 'RC',
|
|
'description': 'Wild mouse coaster with a 100-foot drop.',
|
|
'opening_date': '2007-05-26',
|
|
'coaster_stats': {
|
|
'height_ft': 105,
|
|
'length_ft': 4450,
|
|
'speed_mph': 70,
|
|
'inversions': 0,
|
|
'ride_time_seconds': 180,
|
|
'track_material': 'STEEL',
|
|
'roller_coaster_type': 'WILD_MOUSE',
|
|
'max_drop_height_ft': 100,
|
|
'launch_type': 'CHAIN',
|
|
'trains_count': 2,
|
|
'cars_per_train': 4,
|
|
'seats_per_car': 4,
|
|
}
|
|
},
|
|
{
|
|
'name': 'Time Traveler',
|
|
'park': 'Silver Dollar City',
|
|
'manufacturer': 'Rocky Mountain Construction',
|
|
'designer': 'Alan Schilke',
|
|
'ride_model': 'I-Box Track',
|
|
'category': 'RC',
|
|
'description': 'Wooden coaster with steel I-Box track for smooth riding.',
|
|
'opening_date': '2018-04-28',
|
|
'coaster_stats': {
|
|
'height_ft': 165,
|
|
'length_ft': 5832,
|
|
'speed_mph': 72,
|
|
'inversions': 0,
|
|
'ride_time_seconds': 240,
|
|
'track_material': 'HYBRID',
|
|
'roller_coaster_type': 'SITDOWN',
|
|
'max_drop_height_ft': 155,
|
|
'launch_type': 'CHAIN',
|
|
'trains_count': 2,
|
|
'cars_per_train': 6,
|
|
'seats_per_car': 2,
|
|
}
|
|
},
|
|
]
|
|
|
|
self.rides = {}
|
|
for ride_data in rides_data:
|
|
try:
|
|
park = self.parks[ride_data['park']]
|
|
manufacturer = self.ride_companies.get(
|
|
ride_data.get('manufacturer'))
|
|
designer = self.ride_companies.get(
|
|
ride_data.get('designer'))
|
|
ride_model = self.ride_models.get(
|
|
ride_data.get('ride_model'))
|
|
|
|
ride, created = Ride.objects.get_or_create(
|
|
name=ride_data['name'],
|
|
park=park,
|
|
defaults={
|
|
'description': ride_data['description'],
|
|
'category': ride_data['category'],
|
|
'status': 'OPERATING',
|
|
'opening_date': ride_data['opening_date'],
|
|
'manufacturer': manufacturer,
|
|
'designer': designer,
|
|
'ride_model': ride_model,
|
|
}
|
|
)
|
|
self.rides[ride_data['name']] = ride
|
|
self.stdout.write(
|
|
f' {"Created" if created else "Found"} ride: {ride.name}')
|
|
|
|
# Create roller coaster stats if provided
|
|
if created and 'coaster_stats' in ride_data:
|
|
try:
|
|
stats_data = ride_data['coaster_stats']
|
|
RollerCoasterStats.objects.create(
|
|
ride=ride,
|
|
**stats_data
|
|
)
|
|
except Exception as e:
|
|
self.logger.error(
|
|
f'Error creating stats for ride {ride_data["name"]}: {str(e)}')
|
|
raise
|
|
|
|
except Exception as e:
|
|
self.logger.error(
|
|
f'Error creating ride {ride_data["name"]}: {str(e)}')
|
|
raise
|
|
|
|
except Exception as e:
|
|
self.logger.error(f'Error in create_rides: {str(e)}')
|
|
raise
|
|
|
|
def create_park_areas(self):
|
|
"""Add park areas for variety"""
|
|
self.stdout.write('Creating park areas...')
|
|
|
|
try:
|
|
areas_data = [
|
|
{
|
|
'park': 'Magic Kingdom',
|
|
'areas': [
|
|
{'name': 'Main Street, U.S.A.',
|
|
'description': 'Victorian-era themed entrance corridor'},
|
|
{'name': 'Adventureland',
|
|
'description': 'Exotic tropical places themed area'},
|
|
{'name': 'Frontierland',
|
|
'description': 'American Old West themed area'},
|
|
{'name': 'Liberty Square',
|
|
'description': 'Colonial America themed area'},
|
|
{'name': 'Fantasyland',
|
|
'description': 'Fairy tale themed area'},
|
|
{'name': 'Tomorrowland', 'description': 'Future themed area'},
|
|
]
|
|
},
|
|
{
|
|
'park': 'Universal Studios Florida',
|
|
'areas': [
|
|
{'name': 'Production Central',
|
|
'description': 'Main entrance area with movie-themed attractions'},
|
|
{'name': 'New York',
|
|
'description': 'Themed after New York City streets'},
|
|
{'name': 'San Francisco',
|
|
'description': 'Themed after San Francisco\'s waterfront'},
|
|
{'name': 'The Wizarding World of Harry Potter - Diagon Alley',
|
|
'description': 'Themed after the Harry Potter series'},
|
|
{'name': 'Springfield',
|
|
'description': 'Themed after The Simpsons hometown'},
|
|
]
|
|
},
|
|
{
|
|
'park': 'Cedar Point',
|
|
'areas': [
|
|
{'name': 'Frontiertown',
|
|
'description': 'Western-themed area with multiple roller coasters'},
|
|
{'name': 'Millennium Island',
|
|
'description': 'Home to the Millennium Force roller coaster'},
|
|
{'name': 'Cedar Point Shores',
|
|
'description': 'Waterpark area'},
|
|
{'name': 'Top Thrill Dragster',
|
|
'description': 'Area surrounding the iconic launched coaster'},
|
|
]
|
|
},
|
|
{
|
|
'park': 'Europa-Park',
|
|
'areas': [
|
|
{'name': 'Germany', 'description': 'German-themed area'},
|
|
{'name': 'France', 'description': 'French-themed area'},
|
|
{'name': 'England', 'description': 'English-themed area'},
|
|
{'name': 'Italy', 'description': 'Italian-themed area'},
|
|
{'name': 'Spain', 'description': 'Spanish-themed area'},
|
|
{'name': 'Portugal', 'description': 'Portuguese-themed area'},
|
|
]
|
|
},
|
|
]
|
|
|
|
for area_group in areas_data:
|
|
try:
|
|
park = self.parks[area_group['park']]
|
|
for area_data in area_group['areas']:
|
|
area, created = ParkArea.objects.get_or_create(
|
|
name=area_data['name'],
|
|
park=park,
|
|
defaults={
|
|
'description': area_data['description'],
|
|
'opening_date': park.opening_date,
|
|
}
|
|
)
|
|
self.stdout.write(
|
|
f' {"Created" if created else "Found"} area: {area.name} in {park.name}')
|
|
except Exception as e:
|
|
self.logger.error(
|
|
f'Error creating areas for park {area_group["park"]}: {str(e)}')
|
|
raise
|
|
|
|
except Exception as e:
|
|
self.logger.error(f'Error in create_park_areas: {str(e)}')
|
|
raise
|
|
|
|
def create_reviews(self):
|
|
"""Add sample reviews for testing"""
|
|
self.stdout.write('Creating sample reviews...')
|
|
|
|
try:
|
|
# Create a test user if none exists
|
|
test_user, created = User.objects.get_or_create(
|
|
username='testuser',
|
|
defaults={
|
|
'email': 'test@example.com',
|
|
'first_name': 'Test',
|
|
'last_name': 'User',
|
|
}
|
|
)
|
|
if created:
|
|
test_user.set_password('testpass123')
|
|
test_user.save()
|
|
|
|
# Park reviews
|
|
park_reviews_data = [
|
|
{
|
|
'park': 'Cedar Point',
|
|
'rating': 10,
|
|
'title': 'Best roller coaster park in the world!',
|
|
'content': 'Cedar Point is absolutely incredible. The Millennium Force is a must-ride. The park is clean, well-maintained, and the staff is friendly. Highly recommend!',
|
|
'visit_date': '2023-08-15',
|
|
},
|
|
{
|
|
'park': 'Magic Kingdom',
|
|
'rating': 9,
|
|
'title': 'Magical experience for all ages',
|
|
'content': 'Disney does it again with Magic Kingdom. The attention to detail is amazing and the shows are spectacular. Space Mountain is a classic.',
|
|
'visit_date': '2023-07-20',
|
|
},
|
|
{
|
|
'park': 'Europa-Park',
|
|
'rating': 9,
|
|
'title': 'Europe\'s best theme park',
|
|
'content': 'Europa-Park is fantastic! The theming is incredible and the rides are world-class. Silver Star is absolutely breathtaking.',
|
|
'visit_date': '2023-06-10',
|
|
},
|
|
{
|
|
'park': 'Universal Studios Florida',
|
|
'rating': 8,
|
|
'title': 'Great movie-themed attractions',
|
|
'content': 'Universal has some amazing rides, especially in the Harry Potter area. The theming is top-notch and the shows are entertaining.',
|
|
'visit_date': '2023-05-05',
|
|
},
|
|
]
|
|
|
|
for review_data in park_reviews_data:
|
|
try:
|
|
park = self.parks[review_data['park']]
|
|
review, created = ParkReview.objects.get_or_create(
|
|
park=park,
|
|
user=test_user,
|
|
defaults={
|
|
'rating': review_data['rating'],
|
|
'title': review_data['title'],
|
|
'content': review_data['content'],
|
|
'visit_date': review_data['visit_date'],
|
|
'is_published': True,
|
|
}
|
|
)
|
|
self.stdout.write(
|
|
f' {"Created" if created else "Found"} park review: {review.title}')
|
|
except Exception as e:
|
|
self.logger.error(
|
|
f'Error creating park review for {review_data["park"]}: {str(e)}')
|
|
raise
|
|
|
|
# Ride reviews
|
|
ride_reviews_data = [
|
|
{
|
|
'ride': 'Millennium Force',
|
|
'rating': 10,
|
|
'title': 'The king of roller coasters!',
|
|
'content': 'Absolutely incredible ride! The first drop is breathtaking and the speed is unreal. A must-experience for any coaster enthusiast.',
|
|
'visit_date': '2023-08-15',
|
|
},
|
|
{
|
|
'ride': 'Top Thrill Dragster',
|
|
'rating': 9,
|
|
'title': 'Incredible launch and height',
|
|
'content': 'The launch is intense and reaching the top of the 420-foot tower is amazing. The view from the top is spectacular!',
|
|
'visit_date': '2023-08-16',
|
|
},
|
|
{
|
|
'ride': 'Silver Star',
|
|
'rating': 10,
|
|
'title': 'Best dive coaster in Europe',
|
|
'content': 'The dive drop is incredible! The theming around the ride is beautiful and the overall experience is fantastic.',
|
|
'visit_date': '2023-06-10',
|
|
},
|
|
{
|
|
'ride': 'Space Mountain',
|
|
'rating': 8,
|
|
'title': 'Classic Disney coaster',
|
|
'content': 'A classic that never gets old. The indoor setting and space theme make it unique. Great for all ages.',
|
|
'visit_date': '2023-07-20',
|
|
},
|
|
]
|
|
|
|
for review_data in ride_reviews_data:
|
|
try:
|
|
ride = self.rides[review_data['ride']]
|
|
review, created = RideReview.objects.get_or_create(
|
|
ride=ride,
|
|
user=test_user,
|
|
defaults={
|
|
'rating': review_data['rating'],
|
|
'title': review_data['title'],
|
|
'content': review_data['content'],
|
|
'visit_date': review_data['visit_date'],
|
|
'is_published': True,
|
|
}
|
|
)
|
|
self.stdout.write(
|
|
f' {"Created" if created else "Found"} ride review: {review.title}')
|
|
except Exception as e:
|
|
self.logger.error(
|
|
f'Error creating ride review for {review_data["ride"]}: {str(e)}')
|
|
raise
|
|
|
|
self.stdout.write(self.style.SUCCESS(
|
|
'Sample data creation completed!'))
|
|
|
|
except Exception as e:
|
|
self.logger.error(f'Error in create_reviews: {str(e)}')
|
|
raise
|