here we go

This commit is contained in:
pacnpal
2024-10-31 22:32:01 +00:00
parent c52f14e700
commit 80a9d61ca2
68 changed files with 3114 additions and 1485 deletions

View File

@@ -0,0 +1,99 @@
from django.core.management.base import BaseCommand
from django.db import connection
class Command(BaseCommand):
help = 'Fix historical park records with null location values'
def handle(self, *args, **options):
with connection.cursor() as cursor:
# Make fields nullable temporarily
self.stdout.write('Making fields nullable...')
cursor.execute("""
ALTER TABLE parks_historicalpark
ALTER COLUMN city_id DROP NOT NULL,
ALTER COLUMN region_id DROP NOT NULL,
ALTER COLUMN country_id DROP NOT NULL,
ALTER COLUMN location DROP NOT NULL;
""")
# Get or create default locations
self.stdout.write('Creating default locations if needed...')
# Check if Unknown country exists
cursor.execute("SELECT id FROM cities_light_country WHERE name = 'Unknown' LIMIT 1;")
result = cursor.fetchone()
if not result:
cursor.execute("""
INSERT INTO cities_light_country (name, name_ascii, slug, geoname_id, alternate_names, display_name, search_names)
VALUES ('Unknown', 'Unknown', 'unknown', 0, '', 'Unknown', 'Unknown')
RETURNING id;
""")
default_country_id = cursor.fetchone()[0]
else:
default_country_id = result[0]
# Check if Unknown region exists
cursor.execute("""
SELECT id FROM cities_light_region
WHERE name = 'Unknown' AND country_id = %s LIMIT 1;
""", [default_country_id])
result = cursor.fetchone()
if not result:
cursor.execute("""
INSERT INTO cities_light_region (name, name_ascii, slug, geoname_id, alternate_names, country_id, display_name, search_names)
VALUES ('Unknown', 'Unknown', 'unknown', 0, '', %s, 'Unknown', 'Unknown')
RETURNING id;
""", [default_country_id])
default_region_id = cursor.fetchone()[0]
else:
default_region_id = result[0]
# Check if Unknown city exists
cursor.execute("""
SELECT id FROM cities_light_city
WHERE name = 'Unknown' AND region_id = %s LIMIT 1;
""", [default_region_id])
result = cursor.fetchone()
if not result:
cursor.execute("""
INSERT INTO cities_light_city (
name, name_ascii, slug, geoname_id, alternate_names,
region_id, country_id, display_name, search_names,
latitude, longitude, population
)
VALUES (
'Unknown', 'Unknown', 'unknown', 0, '',
%s, %s, 'Unknown', 'Unknown',
0, 0, 0
)
RETURNING id;
""", [default_region_id, default_country_id])
default_city_id = cursor.fetchone()[0]
else:
default_city_id = result[0]
# Update historical records with null values
self.stdout.write('Updating historical records...')
cursor.execute("""
UPDATE parks_historicalpark
SET country_id = %s,
region_id = %s,
city_id = %s,
location = 'Unknown, Unknown, Unknown'
WHERE country_id IS NULL
OR region_id IS NULL
OR city_id IS NULL
OR location IS NULL;
""", [default_country_id, default_region_id, default_city_id])
# Make fields non-nullable again
self.stdout.write('Making fields non-nullable...')
cursor.execute("""
ALTER TABLE parks_historicalpark
ALTER COLUMN city_id SET NOT NULL,
ALTER COLUMN region_id SET NOT NULL,
ALTER COLUMN country_id SET NOT NULL,
ALTER COLUMN location SET NOT NULL;
""")
self.stdout.write(self.style.SUCCESS('Successfully fixed historical records'))

View File

@@ -0,0 +1,90 @@
from django.core.management.base import BaseCommand
from django.db import connection
class Command(BaseCommand):
help = 'Fix location fields in parks and historical records'
def handle(self, *args, **options):
with connection.cursor() as cursor:
# Check if Unknown country exists
cursor.execute("""
SELECT id FROM cities_light_country WHERE name = 'Unknown' LIMIT 1;
""")
result = cursor.fetchone()
if result:
default_country_id = result[0]
else:
cursor.execute("""
INSERT INTO cities_light_country (name, name_ascii, slug, geoname_id, alternate_names)
VALUES ('Unknown', 'Unknown', 'unknown', 0, '')
RETURNING id;
""")
default_country_id = cursor.fetchone()[0]
# Check if Unknown region exists
cursor.execute("""
SELECT id FROM cities_light_region
WHERE name = 'Unknown' AND country_id = %s LIMIT 1;
""", [default_country_id])
result = cursor.fetchone()
if result:
default_region_id = result[0]
else:
cursor.execute("""
INSERT INTO cities_light_region (name, name_ascii, slug, geoname_id, alternate_names, country_id, display_name)
VALUES ('Unknown', 'Unknown', 'unknown', 0, '', %s, 'Unknown')
RETURNING id;
""", [default_country_id])
default_region_id = cursor.fetchone()[0]
# Check if Unknown city exists
cursor.execute("""
SELECT id FROM cities_light_city
WHERE name = 'Unknown' AND region_id = %s LIMIT 1;
""", [default_region_id])
result = cursor.fetchone()
if result:
default_city_id = result[0]
else:
cursor.execute("""
INSERT INTO cities_light_city (
name, name_ascii, slug, geoname_id, alternate_names,
region_id, country_id, display_name,
latitude, longitude, population
)
VALUES (
'Unknown', 'Unknown', 'unknown', 0, '',
%s, %s, 'Unknown',
0, 0, 0
)
RETURNING id;
""", [default_region_id, default_country_id])
default_city_id = cursor.fetchone()[0]
# Update parks with null locations
cursor.execute("""
UPDATE parks_park
SET country_id = %s,
region_id = %s,
city_id = %s,
location = 'Unknown, Unknown, Unknown'
WHERE country_id IS NULL
OR region_id IS NULL
OR city_id IS NULL
OR location IS NULL;
""", [default_country_id, default_region_id, default_city_id])
# Update historical records with null locations
cursor.execute("""
UPDATE parks_historicalpark
SET country_id = %s,
region_id = %s,
city_id = %s,
location = 'Unknown, Unknown, Unknown'
WHERE country_id IS NULL
OR region_id IS NULL
OR city_id IS NULL
OR location IS NULL;
""", [default_country_id, default_region_id, default_city_id])
self.stdout.write(self.style.SUCCESS('Successfully fixed location fields'))

View File

@@ -10,6 +10,11 @@
"website": "https://disneyworld.disney.go.com/destinations/magic-kingdom/",
"owner": "The Walt Disney Company",
"size_acres": 142,
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Walt_Disney_World_Magic_Kingdom_Cinderella_Castle.jpg/1280px-Walt_Disney_World_Magic_Kingdom_Cinderella_Castle.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/9/96/Magic_Kingdom_Main_Street_USA_Panorama.jpg/1280px-Magic_Kingdom_Main_Street_USA_Panorama.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Magic_Kingdom_-_Cinderella_Castle_at_Night.jpg/1280px-Magic_Kingdom_-_Cinderella_Castle_at_Night.jpg"
],
"rides": [
{
"name": "Space Mountain",
@@ -18,6 +23,10 @@
"status": "OPERATING",
"manufacturer": "Walt Disney Imagineering",
"description": "A high-speed roller coaster in the dark through space.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Magic_Kingdom_Space_Mountain.jpg/1280px-Magic_Kingdom_Space_Mountain.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Space_Mountain_%28Magic_Kingdom%29_entrance.jpg/1280px-Space_Mountain_%28Magic_Kingdom%29_entrance.jpg"
],
"stats": {
"height_ft": 183,
"length_ft": 3196,
@@ -33,6 +42,10 @@
"status": "OPERATING",
"manufacturer": "Walt Disney Imagineering",
"description": "A mine train roller coaster through the Old West.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/9/9c/Big_Thunder_Mountain_Railroad_at_Magic_Kingdom.jpg/1280px-Big_Thunder_Mountain_Railroad_at_Magic_Kingdom.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Big_Thunder_Mountain_Railroad_%28Magic_Kingdom%29.jpg/1280px-Big_Thunder_Mountain_Railroad_%28Magic_Kingdom%29.jpg"
],
"stats": {
"height_ft": 104,
"length_ft": 2671,
@@ -48,6 +61,10 @@
"status": "OPERATING",
"manufacturer": "Vekoma",
"description": "A family roller coaster featuring unique swinging cars.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d6/Seven_Dwarfs_Mine_Train_at_Magic_Kingdom.jpg/1280px-Seven_Dwarfs_Mine_Train_at_Magic_Kingdom.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/f/f5/Seven_Dwarfs_Mine_Train_drop.jpg/1280px-Seven_Dwarfs_Mine_Train_drop.jpg"
],
"stats": {
"height_ft": 112,
"length_ft": 2000,
@@ -62,7 +79,11 @@
"opening_date": "1971-10-01",
"status": "OPERATING",
"manufacturer": "Walt Disney Imagineering",
"description": "A dark ride through a haunted estate."
"description": "A dark ride through a haunted estate.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Haunted_Mansion_at_Magic_Kingdom.jpg/1280px-Haunted_Mansion_at_Magic_Kingdom.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/2/2b/Haunted_Mansion_entrance.jpg/1280px-Haunted_Mansion_entrance.jpg"
]
},
{
"name": "Pirates of the Caribbean",
@@ -70,7 +91,11 @@
"opening_date": "1973-12-15",
"status": "OPERATING",
"manufacturer": "Walt Disney Imagineering",
"description": "A boat ride through pirate-filled Caribbean waters."
"description": "A boat ride through pirate-filled Caribbean waters.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Pirates_of_the_Caribbean_%28Magic_Kingdom%29.jpg/1280px-Pirates_of_the_Caribbean_%28Magic_Kingdom%29.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/8/89/Pirates_of_the_Caribbean_entrance.jpg/1280px-Pirates_of_the_Caribbean_entrance.jpg"
]
}
]
},
@@ -84,6 +109,11 @@
"website": "https://www.cedarpoint.com",
"owner": "Cedar Fair",
"size_acres": 364,
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Cedar_Point_aerial_view.jpg/1280px-Cedar_Point_aerial_view.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Cedar_Point_Beach.jpg/1280px-Cedar_Point_Beach.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cedar_Point_at_dusk.jpg/1280px-Cedar_Point_at_dusk.jpg"
],
"rides": [
{
"name": "Steel Vengeance",
@@ -92,6 +122,10 @@
"status": "OPERATING",
"manufacturer": "Rocky Mountain Construction",
"description": "A hybrid roller coaster featuring multiple inversions.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/8/8c/Steel_Vengeance_at_Cedar_Point.jpg/1280px-Steel_Vengeance_at_Cedar_Point.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/f/f2/Steel_Vengeance_first_drop.jpg/1280px-Steel_Vengeance_first_drop.jpg"
],
"stats": {
"height_ft": 205,
"length_ft": 5740,
@@ -107,6 +141,10 @@
"status": "OPERATING",
"manufacturer": "Intamin",
"description": "A giga coaster with stunning views of Lake Erie.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Millennium_Force_at_Cedar_Point.jpg/1280px-Millennium_Force_at_Cedar_Point.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Millennium_Force_lift_hill.jpg/1280px-Millennium_Force_lift_hill.jpg"
],
"stats": {
"height_ft": 310,
"length_ft": 6595,
@@ -122,6 +160,10 @@
"status": "SBNO",
"manufacturer": "Intamin",
"description": "A strata coaster featuring a 420-foot top hat element.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/0/0c/Top_Thrill_Dragster.jpg/1280px-Top_Thrill_Dragster.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Top_Thrill_Dragster_launch.jpg/1280px-Top_Thrill_Dragster_launch.jpg"
],
"stats": {
"height_ft": 420,
"length_ft": 2800,
@@ -137,6 +179,10 @@
"status": "OPERATING",
"manufacturer": "Intamin",
"description": "A launched roller coaster with multiple inversions.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/3/39/Maverick_at_Cedar_Point.jpg/1280px-Maverick_at_Cedar_Point.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/b/b5/Maverick_first_drop.jpg/1280px-Maverick_first_drop.jpg"
],
"stats": {
"height_ft": 105,
"length_ft": 4450,
@@ -157,6 +203,11 @@
"website": "https://www.universalorlando.com/web/en/us/theme-parks/islands-of-adventure",
"owner": "NBCUniversal",
"size_acres": 110,
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Islands_of_Adventure_entrance.jpg/1280px-Islands_of_Adventure_entrance.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/Hogwarts_Castle_at_Universal%27s_Islands_of_Adventure.jpg/1280px-Hogwarts_Castle_at_Universal%27s_Islands_of_Adventure.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Port_of_Entry_at_Islands_of_Adventure.jpg/1280px-Port_of_Entry_at_Islands_of_Adventure.jpg"
],
"rides": [
{
"name": "Jurassic World VelociCoaster",
@@ -165,6 +216,10 @@
"status": "OPERATING",
"manufacturer": "Intamin",
"description": "A high-speed launch coaster featuring velociraptors.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Jurassic_World_VelociCoaster.jpg/1280px-Jurassic_World_VelociCoaster.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/VelociCoaster_top_hat.jpg/1280px-VelociCoaster_top_hat.jpg"
],
"stats": {
"height_ft": 155,
"length_ft": 4700,
@@ -180,6 +235,10 @@
"status": "OPERATING",
"manufacturer": "Intamin",
"description": "A story coaster through the Forbidden Forest.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Hagrid%27s_Magical_Creatures_Motorbike_Adventure.jpg/1280px-Hagrid%27s_Magical_Creatures_Motorbike_Adventure.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/c/c8/Hagrid%27s_entrance.jpg/1280px-Hagrid%27s_entrance.jpg"
],
"stats": {
"height_ft": 65,
"length_ft": 5053,
@@ -194,7 +253,11 @@
"opening_date": "1999-05-28",
"status": "OPERATING",
"manufacturer": "Oceaneering International",
"description": "A 3D dark ride featuring Spider-Man."
"description": "A 3D dark ride featuring Spider-Man.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/5e/The_Amazing_Adventures_of_Spider-Man.jpg/1280px-The_Amazing_Adventures_of_Spider-Man.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Spider-Man_ride_entrance.jpg/1280px-Spider-Man_ride_entrance.jpg"
]
}
]
},
@@ -208,6 +271,11 @@
"website": "https://www.altontowers.com",
"owner": "Merlin Entertainments",
"size_acres": 910,
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Alton_Towers_aerial_view.jpg/1280px-Alton_Towers_aerial_view.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/3/37/Alton_Towers_mansion.jpg/1280px-Alton_Towers_mansion.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Alton_Towers_gardens.jpg/1280px-Alton_Towers_gardens.jpg"
],
"rides": [
{
"name": "Nemesis",
@@ -216,6 +284,10 @@
"status": "CLOSED",
"manufacturer": "Bolliger & Mabillard",
"description": "An inverted roller coaster through ravines.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/9/98/Nemesis_at_Alton_Towers.jpg/1280px-Nemesis_at_Alton_Towers.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Nemesis_loop.jpg/1280px-Nemesis_loop.jpg"
],
"stats": {
"height_ft": 43,
"length_ft": 2349,
@@ -231,6 +303,10 @@
"status": "OPERATING",
"manufacturer": "Bolliger & Mabillard",
"description": "The world's first vertical drop roller coaster.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/6/67/Oblivion_at_Alton_Towers.jpg/1280px-Oblivion_at_Alton_Towers.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Oblivion_vertical_drop.jpg/1280px-Oblivion_vertical_drop.jpg"
],
"stats": {
"height_ft": 65,
"length_ft": 1804,
@@ -251,6 +327,11 @@
"website": "https://www.europapark.de",
"owner": "Mack Rides",
"size_acres": 235,
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Europa-Park_entrance.jpg/1280px-Europa-Park_entrance.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/f/f2/Europa-Park_aerial_view.jpg/1280px-Europa-Park_aerial_view.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Europa-Park_at_night.jpg/1280px-Europa-Park_at_night.jpg"
],
"rides": [
{
"name": "Silver Star",
@@ -259,6 +340,10 @@
"status": "OPERATING",
"manufacturer": "Bolliger & Mabillard",
"description": "A hypercoaster with stunning views.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/2/24/Silver_Star_at_Europa-Park.jpg/1280px-Silver_Star_at_Europa-Park.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Silver_Star_first_drop.jpg/1280px-Silver_Star_first_drop.jpg"
],
"stats": {
"height_ft": 239,
"length_ft": 4003,
@@ -274,6 +359,10 @@
"status": "OPERATING",
"manufacturer": "Mack Rides",
"description": "A launched roller coaster with multiple inversions.",
"photos": [
"https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Blue_Fire_at_Europa-Park.jpg/1280px-Blue_Fire_at_Europa-Park.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Blue_Fire_launch.jpg/1280px-Blue_Fire_launch.jpg"
],
"stats": {
"height_ft": 125,
"length_ft": 3465,
@@ -285,4 +374,4 @@
]
}
]
}
}

View File

@@ -13,6 +13,7 @@ from faker import Faker
import requests
from io import BytesIO
from PIL import Image
from cities_light.models import City, Country
from parks.models import Park
from rides.models import Ride, RollerCoasterStats
@@ -30,25 +31,30 @@ class Command(BaseCommand):
parser.add_argument('--users', type=int, default=50)
parser.add_argument('--reviews-per-item', type=int, default=10)
def download_and_save_image(self, url, prefix):
def download_and_save_image(self, url):
try:
response = requests.get(url)
img = Image.open(BytesIO(response.content))
img_io = BytesIO()
img.save(img_io, format='JPEG')
img_io.seek(0)
return f'{prefix}_{fake.uuid4()}.jpg', File(img_io)
except:
filename = url.split('/')[-1]
return filename, File(img_io)
except Exception as e:
self.stdout.write(self.style.WARNING(f'Failed to download image {url}: {str(e)}'))
return None, None
def create_users(self, count):
self.stdout.write('Creating users...')
users = []
# Get existing admin user
admin_user = User.objects.get(username='admin')
users.append(admin_user)
self.stdout.write('Added existing admin user')
try:
# Get existing admin user
admin_user = User.objects.get(username='admin')
users.append(admin_user)
self.stdout.write('Added existing admin user')
except User.DoesNotExist:
self.stdout.write(self.style.WARNING('Admin user not found, skipping...'))
# Create regular users using raw SQL
roles = ['USER'] * 20 + ['MODERATOR'] * 3 + ['ADMIN'] * 2
@@ -232,72 +238,87 @@ class Command(BaseCommand):
parks = []
for park_data in seed_data['parks']:
# Create park with company instance
park = Park.objects.create(
name=park_data['name'],
slug=slugify(park_data['name']),
location=park_data['location'],
country=park_data['country'],
opening_date=datetime.strptime(park_data['opening_date'], '%Y-%m-%d').date(),
status=park_data['status'],
description=park_data['description'],
website=park_data['website'],
owner=companies[park_data['owner']],
size_acres=park_data['size_acres']
)
# Add park photos
for _ in range(random.randint(2, 5)):
img_url = f'https://picsum.photos/800/600?random={fake.random_number(5)}'
filename, file = self.download_and_save_image(img_url, 'park')
if filename and file:
Photo.objects.create(
content_object=park,
image=file,
uploaded_by=random.choice(users),
caption=fake.sentence(),
is_approved=True
)
# Create rides for this park
for ride_data in park_data['rides']:
ride = Ride.objects.create(
name=ride_data['name'],
slug=slugify(ride_data['name']),
category=ride_data['category'],
park=park,
status=ride_data['status'],
opening_date=datetime.strptime(ride_data['opening_date'], '%Y-%m-%d').date(),
manufacturer=manufacturers[ride_data['manufacturer']],
description=ride_data['description']
try:
# Get country from cities_light
country = Country.objects.get(code2=park_data['country'])
# Try to find city, but don't require it
city = None
try:
city_name = park_data['location'].split(',')[0].strip()
city = City.objects.filter(name__iexact=city_name, country=country).first()
except:
self.stdout.write(self.style.WARNING(f'City not found for {park_data["name"]}, using location text'))
# Create park
park = Park.objects.create(
name=park_data['name'],
slug=slugify(park_data['name']),
location=park_data['location'],
country=country,
city=city,
opening_date=datetime.strptime(park_data['opening_date'], '%Y-%m-%d').date(),
status=park_data['status'],
description=park_data['description'],
website=park_data['website'],
owner=companies[park_data['owner']],
size_acres=park_data['size_acres']
)
# Add roller coaster stats if applicable
if ride_data['category'] == 'RC' and 'stats' in ride_data:
RollerCoasterStats.objects.create(
ride=ride,
height_ft=ride_data['stats']['height_ft'],
length_ft=ride_data['stats']['length_ft'],
speed_mph=ride_data['stats']['speed_mph'],
inversions=ride_data['stats']['inversions'],
ride_time_seconds=ride_data['stats']['ride_time_seconds']
)
# Add ride photos
for _ in range(random.randint(2, 5)):
img_url = f'https://picsum.photos/800/600?random={fake.random_number(5)}'
filename, file = self.download_and_save_image(img_url, 'ride')
# Add park photos
for photo_url in park_data.get('photos', []):
filename, file = self.download_and_save_image(photo_url)
if filename and file:
Photo.objects.create(
content_object=ride,
content_object=park,
image=file,
uploaded_by=random.choice(users),
caption=fake.sentence(),
caption=f"Photo of {park.name}",
is_approved=True
)
# Create rides for this park
for ride_data in park_data['rides']:
ride = Ride.objects.create(
name=ride_data['name'],
slug=slugify(ride_data['name']),
category=ride_data['category'],
park=park,
status=ride_data['status'],
opening_date=datetime.strptime(ride_data['opening_date'], '%Y-%m-%d').date(),
manufacturer=manufacturers[ride_data['manufacturer']],
description=ride_data['description']
)
# Add roller coaster stats if applicable
if ride_data['category'] == 'RC' and 'stats' in ride_data:
RollerCoasterStats.objects.create(
ride=ride,
height_ft=ride_data['stats']['height_ft'],
length_ft=ride_data['stats']['length_ft'],
speed_mph=ride_data['stats']['speed_mph'],
inversions=ride_data['stats']['inversions'],
ride_time_seconds=ride_data['stats']['ride_time_seconds']
)
# Add ride photos
for photo_url in ride_data.get('photos', []):
filename, file = self.download_and_save_image(photo_url)
if filename and file:
Photo.objects.create(
content_object=ride,
image=file,
uploaded_by=random.choice(users),
caption=f"Photo of {ride.name}",
is_approved=True
)
parks.append(park)
self.stdout.write(f'Created park and rides: {park.name}')
parks.append(park)
self.stdout.write(f'Created park and rides: {park.name}')
except Exception as e:
self.stdout.write(self.style.ERROR(f'Failed to create park {park_data["name"]}: {str(e)}'))
continue
return parks