This commit is contained in:
pacnpal
2026-01-08 13:44:37 -05:00
parent 40cba5bdb2
commit fe960e8b62
21 changed files with 2008 additions and 59 deletions

View File

@@ -0,0 +1,432 @@
# Generated by Django 5.2.9 on 2026-01-07 20:30
import django.contrib.postgres.fields
import pgtrigger.compiler
import pgtrigger.migrations
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rides', '0033_add_ride_subtype_and_age'),
]
operations = [
pgtrigger.migrations.RemoveTrigger(
model_name='ride',
name='insert_insert',
),
pgtrigger.migrations.RemoveTrigger(
model_name='ride',
name='update_update',
),
migrations.AddField(
model_name='ride',
name='animatronics_count',
field=models.PositiveIntegerField(blank=True, help_text='Number of animatronic figures', null=True),
),
migrations.AddField(
model_name='ride',
name='arm_length_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Length of ride arm in meters', max_digits=5, null=True),
),
migrations.AddField(
model_name='ride',
name='boat_capacity',
field=models.PositiveIntegerField(blank=True, help_text='Number of passengers per boat/vehicle', null=True),
),
migrations.AddField(
model_name='ride',
name='character_theme',
field=models.CharField(blank=True, help_text='Character or IP theme (e.g., Paw Patrol, Sesame Street)', max_length=200),
),
migrations.AddField(
model_name='ride',
name='coaster_type',
field=models.CharField(blank=True, help_text='Coaster structure type: steel, wood, or hybrid', max_length=20),
),
migrations.AddField(
model_name='ride',
name='drop_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Maximum drop height in meters', max_digits=6, null=True),
),
migrations.AddField(
model_name='ride',
name='educational_theme',
field=models.CharField(blank=True, help_text='Educational or learning theme if applicable', max_length=200),
),
migrations.AddField(
model_name='ride',
name='flume_type',
field=models.CharField(blank=True, help_text='Type of flume or water channel', max_length=100),
),
migrations.AddField(
model_name='ride',
name='gforce_max',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Maximum G-force experienced', max_digits=4, null=True),
),
migrations.AddField(
model_name='ride',
name='height_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Height of the ride structure in meters', max_digits=6, null=True),
),
migrations.AddField(
model_name='ride',
name='intensity_level',
field=models.CharField(blank=True, help_text='Intensity classification: family, thrill, or extreme', max_length=20),
),
migrations.AddField(
model_name='ride',
name='length_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Total track/ride length in meters', max_digits=8, null=True),
),
migrations.AddField(
model_name='ride',
name='max_age',
field=models.PositiveIntegerField(blank=True, help_text='Maximum recommended age in years', null=True),
),
migrations.AddField(
model_name='ride',
name='max_height_reached_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Maximum height reached during ride cycle in meters', max_digits=6, null=True),
),
migrations.AddField(
model_name='ride',
name='max_speed_kmh',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Maximum speed in kilometers per hour', max_digits=6, null=True),
),
migrations.AddField(
model_name='ride',
name='min_age',
field=models.PositiveIntegerField(blank=True, help_text='Minimum recommended age in years', null=True),
),
migrations.AddField(
model_name='ride',
name='motion_pattern',
field=models.CharField(blank=True, help_text="Description of the ride's motion pattern", max_length=200),
),
migrations.AddField(
model_name='ride',
name='platform_count',
field=models.PositiveIntegerField(blank=True, help_text='Number of ride platforms or gondolas', null=True),
),
migrations.AddField(
model_name='ride',
name='projection_type',
field=models.CharField(blank=True, help_text='Type of projection technology used', max_length=100),
),
migrations.AddField(
model_name='ride',
name='propulsion_method',
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50), blank=True, default=list, help_text="Propulsion methods (e.g., ['chain_lift', 'lsm'])", size=None),
),
migrations.AddField(
model_name='ride',
name='ride_system',
field=models.CharField(blank=True, help_text='Ride system type (e.g., trackless, omnimover)', max_length=100),
),
migrations.AddField(
model_name='ride',
name='rotation_speed_rpm',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Rotation speed in revolutions per minute', max_digits=6, null=True),
),
migrations.AddField(
model_name='ride',
name='rotation_type',
field=models.CharField(blank=True, help_text='Rotation axis: horizontal, vertical, multi_axis, pendulum, or none', max_length=20),
),
migrations.AddField(
model_name='ride',
name='round_trip_duration_seconds',
field=models.PositiveIntegerField(blank=True, help_text='Duration of a complete round trip in seconds', null=True),
),
migrations.AddField(
model_name='ride',
name='route_length_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Total route length in meters', max_digits=8, null=True),
),
migrations.AddField(
model_name='ride',
name='scenes_count',
field=models.PositiveIntegerField(blank=True, help_text='Number of distinct scenes or show sections', null=True),
),
migrations.AddField(
model_name='ride',
name='seating_type',
field=models.CharField(blank=True, help_text='Seating configuration: sit_down, inverted, flying, stand_up, etc.', max_length=20),
),
migrations.AddField(
model_name='ride',
name='show_duration_seconds',
field=models.PositiveIntegerField(blank=True, help_text='Duration of show elements in seconds', null=True),
),
migrations.AddField(
model_name='ride',
name='splash_height_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Maximum splash height in meters', max_digits=5, null=True),
),
migrations.AddField(
model_name='ride',
name='stations_count',
field=models.PositiveIntegerField(blank=True, help_text='Number of stations or stops', null=True),
),
migrations.AddField(
model_name='ride',
name='story_description',
field=models.TextField(blank=True, help_text='Narrative or story description for the ride'),
),
migrations.AddField(
model_name='ride',
name='support_material',
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50), blank=True, default=list, help_text='Support structure material types', size=None),
),
migrations.AddField(
model_name='ride',
name='swing_angle_degrees',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Maximum swing angle in degrees', max_digits=5, null=True),
),
migrations.AddField(
model_name='ride',
name='theme_name',
field=models.CharField(blank=True, help_text='Primary theme or IP name', max_length=200),
),
migrations.AddField(
model_name='ride',
name='track_material',
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50), blank=True, default=list, help_text="Track material types (e.g., ['steel', 'wood'])", size=None),
),
migrations.AddField(
model_name='ride',
name='transport_type',
field=models.CharField(blank=True, help_text='Transport mode: train, monorail, skylift, ferry, peoplemover, or cable_car', max_length=20),
),
migrations.AddField(
model_name='ride',
name='vehicle_capacity',
field=models.PositiveIntegerField(blank=True, help_text='Passenger capacity per vehicle', null=True),
),
migrations.AddField(
model_name='ride',
name='vehicles_count',
field=models.PositiveIntegerField(blank=True, help_text='Number of vehicles in operation', null=True),
),
migrations.AddField(
model_name='ride',
name='water_depth_cm',
field=models.PositiveIntegerField(blank=True, help_text='Water depth in centimeters', null=True),
),
migrations.AddField(
model_name='ride',
name='wetness_level',
field=models.CharField(blank=True, help_text='Expected wetness: dry, light, moderate, or soaked', max_length=20),
),
migrations.AddField(
model_name='rideevent',
name='animatronics_count',
field=models.PositiveIntegerField(blank=True, help_text='Number of animatronic figures', null=True),
),
migrations.AddField(
model_name='rideevent',
name='arm_length_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Length of ride arm in meters', max_digits=5, null=True),
),
migrations.AddField(
model_name='rideevent',
name='boat_capacity',
field=models.PositiveIntegerField(blank=True, help_text='Number of passengers per boat/vehicle', null=True),
),
migrations.AddField(
model_name='rideevent',
name='character_theme',
field=models.CharField(blank=True, help_text='Character or IP theme (e.g., Paw Patrol, Sesame Street)', max_length=200),
),
migrations.AddField(
model_name='rideevent',
name='coaster_type',
field=models.CharField(blank=True, help_text='Coaster structure type: steel, wood, or hybrid', max_length=20),
),
migrations.AddField(
model_name='rideevent',
name='drop_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Maximum drop height in meters', max_digits=6, null=True),
),
migrations.AddField(
model_name='rideevent',
name='educational_theme',
field=models.CharField(blank=True, help_text='Educational or learning theme if applicable', max_length=200),
),
migrations.AddField(
model_name='rideevent',
name='flume_type',
field=models.CharField(blank=True, help_text='Type of flume or water channel', max_length=100),
),
migrations.AddField(
model_name='rideevent',
name='gforce_max',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Maximum G-force experienced', max_digits=4, null=True),
),
migrations.AddField(
model_name='rideevent',
name='height_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Height of the ride structure in meters', max_digits=6, null=True),
),
migrations.AddField(
model_name='rideevent',
name='intensity_level',
field=models.CharField(blank=True, help_text='Intensity classification: family, thrill, or extreme', max_length=20),
),
migrations.AddField(
model_name='rideevent',
name='length_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Total track/ride length in meters', max_digits=8, null=True),
),
migrations.AddField(
model_name='rideevent',
name='max_age',
field=models.PositiveIntegerField(blank=True, help_text='Maximum recommended age in years', null=True),
),
migrations.AddField(
model_name='rideevent',
name='max_height_reached_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Maximum height reached during ride cycle in meters', max_digits=6, null=True),
),
migrations.AddField(
model_name='rideevent',
name='max_speed_kmh',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Maximum speed in kilometers per hour', max_digits=6, null=True),
),
migrations.AddField(
model_name='rideevent',
name='min_age',
field=models.PositiveIntegerField(blank=True, help_text='Minimum recommended age in years', null=True),
),
migrations.AddField(
model_name='rideevent',
name='motion_pattern',
field=models.CharField(blank=True, help_text="Description of the ride's motion pattern", max_length=200),
),
migrations.AddField(
model_name='rideevent',
name='platform_count',
field=models.PositiveIntegerField(blank=True, help_text='Number of ride platforms or gondolas', null=True),
),
migrations.AddField(
model_name='rideevent',
name='projection_type',
field=models.CharField(blank=True, help_text='Type of projection technology used', max_length=100),
),
migrations.AddField(
model_name='rideevent',
name='propulsion_method',
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50), blank=True, default=list, help_text="Propulsion methods (e.g., ['chain_lift', 'lsm'])", size=None),
),
migrations.AddField(
model_name='rideevent',
name='ride_system',
field=models.CharField(blank=True, help_text='Ride system type (e.g., trackless, omnimover)', max_length=100),
),
migrations.AddField(
model_name='rideevent',
name='rotation_speed_rpm',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Rotation speed in revolutions per minute', max_digits=6, null=True),
),
migrations.AddField(
model_name='rideevent',
name='rotation_type',
field=models.CharField(blank=True, help_text='Rotation axis: horizontal, vertical, multi_axis, pendulum, or none', max_length=20),
),
migrations.AddField(
model_name='rideevent',
name='round_trip_duration_seconds',
field=models.PositiveIntegerField(blank=True, help_text='Duration of a complete round trip in seconds', null=True),
),
migrations.AddField(
model_name='rideevent',
name='route_length_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Total route length in meters', max_digits=8, null=True),
),
migrations.AddField(
model_name='rideevent',
name='scenes_count',
field=models.PositiveIntegerField(blank=True, help_text='Number of distinct scenes or show sections', null=True),
),
migrations.AddField(
model_name='rideevent',
name='seating_type',
field=models.CharField(blank=True, help_text='Seating configuration: sit_down, inverted, flying, stand_up, etc.', max_length=20),
),
migrations.AddField(
model_name='rideevent',
name='show_duration_seconds',
field=models.PositiveIntegerField(blank=True, help_text='Duration of show elements in seconds', null=True),
),
migrations.AddField(
model_name='rideevent',
name='splash_height_meters',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Maximum splash height in meters', max_digits=5, null=True),
),
migrations.AddField(
model_name='rideevent',
name='stations_count',
field=models.PositiveIntegerField(blank=True, help_text='Number of stations or stops', null=True),
),
migrations.AddField(
model_name='rideevent',
name='story_description',
field=models.TextField(blank=True, help_text='Narrative or story description for the ride'),
),
migrations.AddField(
model_name='rideevent',
name='support_material',
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50), blank=True, default=list, help_text='Support structure material types', size=None),
),
migrations.AddField(
model_name='rideevent',
name='swing_angle_degrees',
field=models.DecimalField(blank=True, decimal_places=2, help_text='Maximum swing angle in degrees', max_digits=5, null=True),
),
migrations.AddField(
model_name='rideevent',
name='theme_name',
field=models.CharField(blank=True, help_text='Primary theme or IP name', max_length=200),
),
migrations.AddField(
model_name='rideevent',
name='track_material',
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50), blank=True, default=list, help_text="Track material types (e.g., ['steel', 'wood'])", size=None),
),
migrations.AddField(
model_name='rideevent',
name='transport_type',
field=models.CharField(blank=True, help_text='Transport mode: train, monorail, skylift, ferry, peoplemover, or cable_car', max_length=20),
),
migrations.AddField(
model_name='rideevent',
name='vehicle_capacity',
field=models.PositiveIntegerField(blank=True, help_text='Passenger capacity per vehicle', null=True),
),
migrations.AddField(
model_name='rideevent',
name='vehicles_count',
field=models.PositiveIntegerField(blank=True, help_text='Number of vehicles in operation', null=True),
),
migrations.AddField(
model_name='rideevent',
name='water_depth_cm',
field=models.PositiveIntegerField(blank=True, help_text='Water depth in centimeters', null=True),
),
migrations.AddField(
model_name='rideevent',
name='wetness_level',
field=models.CharField(blank=True, help_text='Expected wetness: dry, light, moderate, or soaked', max_length=20),
),
pgtrigger.migrations.AddTrigger(
model_name='ride',
trigger=pgtrigger.compiler.Trigger(name='insert_insert', sql=pgtrigger.compiler.UpsertTriggerSql(func='INSERT INTO "rides_rideevent" ("age_requirement", "animatronics_count", "arm_length_meters", "average_rating", "banner_image_id", "boat_capacity", "capacity_per_hour", "card_image_id", "category", "character_theme", "closing_date", "closing_date_precision", "coaster_type", "created_at", "description", "designer_id", "drop_meters", "educational_theme", "flume_type", "gforce_max", "height_meters", "id", "intensity_level", "length_meters", "manufacturer_id", "max_age", "max_height_in", "max_height_reached_meters", "max_speed_kmh", "min_age", "min_height_in", "motion_pattern", "name", "opening_date", "opening_date_precision", "opening_year", "park_area_id", "park_id", "park_url", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "platform_count", "post_closing_status", "projection_type", "propulsion_method", "ride_duration_seconds", "ride_model_id", "ride_sub_type", "ride_system", "rotation_speed_rpm", "rotation_type", "round_trip_duration_seconds", "route_length_meters", "scenes_count", "search_text", "seating_type", "show_duration_seconds", "slug", "splash_height_meters", "stations_count", "status", "status_since", "story_description", "support_material", "swing_angle_degrees", "theme_name", "track_material", "transport_type", "updated_at", "url", "vehicle_capacity", "vehicles_count", "water_depth_cm", "wetness_level") VALUES (NEW."age_requirement", NEW."animatronics_count", NEW."arm_length_meters", NEW."average_rating", NEW."banner_image_id", NEW."boat_capacity", NEW."capacity_per_hour", NEW."card_image_id", NEW."category", NEW."character_theme", NEW."closing_date", NEW."closing_date_precision", NEW."coaster_type", NEW."created_at", NEW."description", NEW."designer_id", NEW."drop_meters", NEW."educational_theme", NEW."flume_type", NEW."gforce_max", NEW."height_meters", NEW."id", NEW."intensity_level", NEW."length_meters", NEW."manufacturer_id", NEW."max_age", NEW."max_height_in", NEW."max_height_reached_meters", NEW."max_speed_kmh", NEW."min_age", NEW."min_height_in", NEW."motion_pattern", NEW."name", NEW."opening_date", NEW."opening_date_precision", NEW."opening_year", NEW."park_area_id", NEW."park_id", NEW."park_url", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."platform_count", NEW."post_closing_status", NEW."projection_type", NEW."propulsion_method", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."ride_sub_type", NEW."ride_system", NEW."rotation_speed_rpm", NEW."rotation_type", NEW."round_trip_duration_seconds", NEW."route_length_meters", NEW."scenes_count", NEW."search_text", NEW."seating_type", NEW."show_duration_seconds", NEW."slug", NEW."splash_height_meters", NEW."stations_count", NEW."status", NEW."status_since", NEW."story_description", NEW."support_material", NEW."swing_angle_degrees", NEW."theme_name", NEW."track_material", NEW."transport_type", NEW."updated_at", NEW."url", NEW."vehicle_capacity", NEW."vehicles_count", NEW."water_depth_cm", NEW."wetness_level"); RETURN NULL;', hash='0515185b26eb9635e7b7f7d52cfa87b90636c409', operation='INSERT', pgid='pgtrigger_insert_insert_52074', table='rides_ride', when='AFTER')),
),
pgtrigger.migrations.AddTrigger(
model_name='ride',
trigger=pgtrigger.compiler.Trigger(name='update_update', sql=pgtrigger.compiler.UpsertTriggerSql(condition='WHEN (OLD.* IS DISTINCT FROM NEW.*)', func='INSERT INTO "rides_rideevent" ("age_requirement", "animatronics_count", "arm_length_meters", "average_rating", "banner_image_id", "boat_capacity", "capacity_per_hour", "card_image_id", "category", "character_theme", "closing_date", "closing_date_precision", "coaster_type", "created_at", "description", "designer_id", "drop_meters", "educational_theme", "flume_type", "gforce_max", "height_meters", "id", "intensity_level", "length_meters", "manufacturer_id", "max_age", "max_height_in", "max_height_reached_meters", "max_speed_kmh", "min_age", "min_height_in", "motion_pattern", "name", "opening_date", "opening_date_precision", "opening_year", "park_area_id", "park_id", "park_url", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "platform_count", "post_closing_status", "projection_type", "propulsion_method", "ride_duration_seconds", "ride_model_id", "ride_sub_type", "ride_system", "rotation_speed_rpm", "rotation_type", "round_trip_duration_seconds", "route_length_meters", "scenes_count", "search_text", "seating_type", "show_duration_seconds", "slug", "splash_height_meters", "stations_count", "status", "status_since", "story_description", "support_material", "swing_angle_degrees", "theme_name", "track_material", "transport_type", "updated_at", "url", "vehicle_capacity", "vehicles_count", "water_depth_cm", "wetness_level") VALUES (NEW."age_requirement", NEW."animatronics_count", NEW."arm_length_meters", NEW."average_rating", NEW."banner_image_id", NEW."boat_capacity", NEW."capacity_per_hour", NEW."card_image_id", NEW."category", NEW."character_theme", NEW."closing_date", NEW."closing_date_precision", NEW."coaster_type", NEW."created_at", NEW."description", NEW."designer_id", NEW."drop_meters", NEW."educational_theme", NEW."flume_type", NEW."gforce_max", NEW."height_meters", NEW."id", NEW."intensity_level", NEW."length_meters", NEW."manufacturer_id", NEW."max_age", NEW."max_height_in", NEW."max_height_reached_meters", NEW."max_speed_kmh", NEW."min_age", NEW."min_height_in", NEW."motion_pattern", NEW."name", NEW."opening_date", NEW."opening_date_precision", NEW."opening_year", NEW."park_area_id", NEW."park_id", NEW."park_url", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."platform_count", NEW."post_closing_status", NEW."projection_type", NEW."propulsion_method", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."ride_sub_type", NEW."ride_system", NEW."rotation_speed_rpm", NEW."rotation_type", NEW."round_trip_duration_seconds", NEW."route_length_meters", NEW."scenes_count", NEW."search_text", NEW."seating_type", NEW."show_duration_seconds", NEW."slug", NEW."splash_height_meters", NEW."stations_count", NEW."status", NEW."status_since", NEW."story_description", NEW."support_material", NEW."swing_angle_degrees", NEW."theme_name", NEW."track_material", NEW."transport_type", NEW."updated_at", NEW."url", NEW."vehicle_capacity", NEW."vehicles_count", NEW."water_depth_cm", NEW."wetness_level"); RETURN NULL;', hash='e0bb5999b75a6d10f73651cba99c40e06bb2b49c', operation='UPDATE', pgid='pgtrigger_update_update_4917a', table='rides_ride', when='AFTER')),
),
]

View File

@@ -0,0 +1,119 @@
# Generated by Django 5.2.9 on 2026-01-07 21:01
import django.db.models.deletion
import pgtrigger.compiler
import pgtrigger.migrations
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('parks', '0028_add_date_precision_fields'),
('rides', '0034_add_ride_category_fields'),
]
operations = [
pgtrigger.migrations.RemoveTrigger(
model_name='company',
name='insert_insert',
),
pgtrigger.migrations.RemoveTrigger(
model_name='company',
name='update_update',
),
pgtrigger.migrations.RemoveTrigger(
model_name='ridemodel',
name='insert_insert',
),
pgtrigger.migrations.RemoveTrigger(
model_name='ridemodel',
name='update_update',
),
migrations.AddField(
model_name='company',
name='banner_image_id',
field=models.CharField(blank=True, help_text='Cloudflare image ID for banner image', max_length=255),
),
migrations.AddField(
model_name='company',
name='card_image_id',
field=models.CharField(blank=True, help_text='Cloudflare image ID for card image', max_length=255),
),
migrations.AddField(
model_name='company',
name='founded_date_precision',
field=models.CharField(blank=True, choices=[('exact', 'Exact'), ('month', 'Month'), ('year', 'Year'), ('decade', 'Decade'), ('century', 'Century'), ('approximate', 'Approximate')], default='', help_text='Precision of the founded date', max_length=20),
),
migrations.AddField(
model_name='company',
name='founded_year',
field=models.PositiveIntegerField(blank=True, help_text='Year the company was founded (alternative to founded_date)', null=True),
),
migrations.AddField(
model_name='company',
name='headquarters_location',
field=models.CharField(blank=True, help_text="Headquarters location description (e.g., 'Los Angeles, CA, USA')", max_length=200),
),
migrations.AddField(
model_name='company',
name='location',
field=models.ForeignKey(blank=True, help_text='Linked location record for headquarters', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='companies', to='parks.parklocation'),
),
migrations.AddField(
model_name='companyevent',
name='banner_image_id',
field=models.CharField(blank=True, help_text='Cloudflare image ID for banner image', max_length=255),
),
migrations.AddField(
model_name='companyevent',
name='card_image_id',
field=models.CharField(blank=True, help_text='Cloudflare image ID for card image', max_length=255),
),
migrations.AddField(
model_name='companyevent',
name='founded_date_precision',
field=models.CharField(blank=True, choices=[('exact', 'Exact'), ('month', 'Month'), ('year', 'Year'), ('decade', 'Decade'), ('century', 'Century'), ('approximate', 'Approximate')], default='', help_text='Precision of the founded date', max_length=20),
),
migrations.AddField(
model_name='companyevent',
name='founded_year',
field=models.PositiveIntegerField(blank=True, help_text='Year the company was founded (alternative to founded_date)', null=True),
),
migrations.AddField(
model_name='companyevent',
name='headquarters_location',
field=models.CharField(blank=True, help_text="Headquarters location description (e.g., 'Los Angeles, CA, USA')", max_length=200),
),
migrations.AddField(
model_name='companyevent',
name='location',
field=models.ForeignKey(blank=True, db_constraint=False, help_text='Linked location record for headquarters', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', related_query_name='+', to='parks.parklocation'),
),
migrations.AddField(
model_name='ridemodel',
name='ride_type',
field=models.CharField(blank=True, help_text="Specific ride type within the category (e.g., 'Flying Coaster', 'Inverted Coaster')", max_length=100),
),
migrations.AddField(
model_name='ridemodelevent',
name='ride_type',
field=models.CharField(blank=True, help_text="Specific ride type within the category (e.g., 'Flying Coaster', 'Inverted Coaster')", max_length=100),
),
pgtrigger.migrations.AddTrigger(
model_name='company',
trigger=pgtrigger.compiler.Trigger(name='insert_insert', sql=pgtrigger.compiler.UpsertTriggerSql(func='INSERT INTO "rides_companyevent" ("banner_image_id", "card_image_id", "coasters_count", "created_at", "description", "founded_date", "founded_date_precision", "founded_year", "headquarters_location", "id", "location_id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rides_count", "roles", "slug", "updated_at", "url", "website") VALUES (NEW."banner_image_id", NEW."card_image_id", NEW."coasters_count", NEW."created_at", NEW."description", NEW."founded_date", NEW."founded_date_precision", NEW."founded_year", NEW."headquarters_location", NEW."id", NEW."location_id", NEW."name", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."rides_count", NEW."roles", NEW."slug", NEW."updated_at", NEW."url", NEW."website"); RETURN NULL;', hash='d1efc807d08a85e448a3294e70abb85e1c9c40ff', operation='INSERT', pgid='pgtrigger_insert_insert_e7194', table='rides_company', when='AFTER')),
),
pgtrigger.migrations.AddTrigger(
model_name='company',
trigger=pgtrigger.compiler.Trigger(name='update_update', sql=pgtrigger.compiler.UpsertTriggerSql(condition='WHEN (OLD.* IS DISTINCT FROM NEW.*)', func='INSERT INTO "rides_companyevent" ("banner_image_id", "card_image_id", "coasters_count", "created_at", "description", "founded_date", "founded_date_precision", "founded_year", "headquarters_location", "id", "location_id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rides_count", "roles", "slug", "updated_at", "url", "website") VALUES (NEW."banner_image_id", NEW."card_image_id", NEW."coasters_count", NEW."created_at", NEW."description", NEW."founded_date", NEW."founded_date_precision", NEW."founded_year", NEW."headquarters_location", NEW."id", NEW."location_id", NEW."name", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."rides_count", NEW."roles", NEW."slug", NEW."updated_at", NEW."url", NEW."website"); RETURN NULL;', hash='dd4644183deefdfa27ec6d282c6da0c09d4df927', operation='UPDATE', pgid='pgtrigger_update_update_456a8', table='rides_company', when='AFTER')),
),
pgtrigger.migrations.AddTrigger(
model_name='ridemodel',
trigger=pgtrigger.compiler.Trigger(name='insert_insert', sql=pgtrigger.compiler.UpsertTriggerSql(func='INSERT INTO "rides_ridemodelevent" ("category", "created_at", "description", "first_installation_year", "id", "is_discontinued", "last_installation_year", "manufacturer_id", "meta_description", "meta_title", "name", "notable_features", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "primary_image_id", "restraint_system", "ride_type", "slug", "support_structure", "target_market", "total_installations", "track_type", "train_configuration", "typical_capacity_range_max", "typical_capacity_range_min", "typical_height_range_max_ft", "typical_height_range_min_ft", "typical_speed_range_max_mph", "typical_speed_range_min_mph", "updated_at", "url") VALUES (NEW."category", NEW."created_at", NEW."description", NEW."first_installation_year", NEW."id", NEW."is_discontinued", NEW."last_installation_year", NEW."manufacturer_id", NEW."meta_description", NEW."meta_title", NEW."name", NEW."notable_features", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."primary_image_id", NEW."restraint_system", NEW."ride_type", NEW."slug", NEW."support_structure", NEW."target_market", NEW."total_installations", NEW."track_type", NEW."train_configuration", NEW."typical_capacity_range_max", NEW."typical_capacity_range_min", NEW."typical_height_range_max_ft", NEW."typical_height_range_min_ft", NEW."typical_speed_range_max_mph", NEW."typical_speed_range_min_mph", NEW."updated_at", NEW."url"); RETURN NULL;', hash='715219f75d39aa2d59ffe836084dab943a322c5f', operation='INSERT', pgid='pgtrigger_insert_insert_0aaee', table='rides_ridemodel', when='AFTER')),
),
pgtrigger.migrations.AddTrigger(
model_name='ridemodel',
trigger=pgtrigger.compiler.Trigger(name='update_update', sql=pgtrigger.compiler.UpsertTriggerSql(condition='WHEN (OLD.* IS DISTINCT FROM NEW.*)', func='INSERT INTO "rides_ridemodelevent" ("category", "created_at", "description", "first_installation_year", "id", "is_discontinued", "last_installation_year", "manufacturer_id", "meta_description", "meta_title", "name", "notable_features", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "primary_image_id", "restraint_system", "ride_type", "slug", "support_structure", "target_market", "total_installations", "track_type", "train_configuration", "typical_capacity_range_max", "typical_capacity_range_min", "typical_height_range_max_ft", "typical_height_range_min_ft", "typical_speed_range_max_mph", "typical_speed_range_min_mph", "updated_at", "url") VALUES (NEW."category", NEW."created_at", NEW."description", NEW."first_installation_year", NEW."id", NEW."is_discontinued", NEW."last_installation_year", NEW."manufacturer_id", NEW."meta_description", NEW."meta_title", NEW."name", NEW."notable_features", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."primary_image_id", NEW."restraint_system", NEW."ride_type", NEW."slug", NEW."support_structure", NEW."target_market", NEW."total_installations", NEW."track_type", NEW."train_configuration", NEW."typical_capacity_range_max", NEW."typical_capacity_range_min", NEW."typical_height_range_max_ft", NEW."typical_height_range_min_ft", NEW."typical_speed_range_max_mph", NEW."typical_speed_range_min_mph", NEW."updated_at", NEW."url"); RETURN NULL;', hash='4f1d59b4ef9ddd207f7e4a56843d830ab67cff38', operation='UPDATE', pgid='pgtrigger_update_update_0ca1a', table='rides_ridemodel', when='AFTER')),
),
]

View File

@@ -0,0 +1,87 @@
# Generated by Django 5.2.9 on 2026-01-08 01:40
import pgtrigger.compiler
import pgtrigger.migrations
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rides', '0035_add_company_and_ridemodel_fields'),
]
operations = [
pgtrigger.migrations.RemoveTrigger(
model_name='company',
name='insert_insert',
),
pgtrigger.migrations.RemoveTrigger(
model_name='company',
name='update_update',
),
pgtrigger.migrations.RemoveTrigger(
model_name='ride',
name='insert_insert',
),
pgtrigger.migrations.RemoveTrigger(
model_name='ride',
name='update_update',
),
migrations.AddField(
model_name='company',
name='person_type',
field=models.CharField(blank=True, choices=[('company', 'Company'), ('individual', 'Individual'), ('firm', 'Firm'), ('organization', 'Organization')], default='company', help_text='Type of entity (company, individual, firm, organization)', max_length=20),
),
migrations.AddField(
model_name='companyevent',
name='person_type',
field=models.CharField(blank=True, choices=[('company', 'Company'), ('individual', 'Individual'), ('firm', 'Firm'), ('organization', 'Organization')], default='company', help_text='Type of entity (company, individual, firm, organization)', max_length=20),
),
migrations.AddField(
model_name='ride',
name='duration_seconds',
field=models.PositiveIntegerField(blank=True, help_text='Ride duration in seconds', null=True),
),
migrations.AddField(
model_name='ride',
name='height_requirement_cm',
field=models.PositiveIntegerField(blank=True, help_text='Minimum height requirement in centimeters', null=True),
),
migrations.AddField(
model_name='ride',
name='inversions_count',
field=models.PositiveIntegerField(blank=True, help_text='Number of inversions (for coasters)', null=True),
),
migrations.AddField(
model_name='rideevent',
name='duration_seconds',
field=models.PositiveIntegerField(blank=True, help_text='Ride duration in seconds', null=True),
),
migrations.AddField(
model_name='rideevent',
name='height_requirement_cm',
field=models.PositiveIntegerField(blank=True, help_text='Minimum height requirement in centimeters', null=True),
),
migrations.AddField(
model_name='rideevent',
name='inversions_count',
field=models.PositiveIntegerField(blank=True, help_text='Number of inversions (for coasters)', null=True),
),
pgtrigger.migrations.AddTrigger(
model_name='company',
trigger=pgtrigger.compiler.Trigger(name='insert_insert', sql=pgtrigger.compiler.UpsertTriggerSql(func='INSERT INTO "rides_companyevent" ("banner_image_id", "card_image_id", "coasters_count", "created_at", "description", "founded_date", "founded_date_precision", "founded_year", "headquarters_location", "id", "location_id", "name", "person_type", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rides_count", "roles", "slug", "updated_at", "url", "website") VALUES (NEW."banner_image_id", NEW."card_image_id", NEW."coasters_count", NEW."created_at", NEW."description", NEW."founded_date", NEW."founded_date_precision", NEW."founded_year", NEW."headquarters_location", NEW."id", NEW."location_id", NEW."name", NEW."person_type", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."rides_count", NEW."roles", NEW."slug", NEW."updated_at", NEW."url", NEW."website"); RETURN NULL;', hash='636ad62fbef5026486e8eb22d7b3ad3a08b08972', operation='INSERT', pgid='pgtrigger_insert_insert_e7194', table='rides_company', when='AFTER')),
),
pgtrigger.migrations.AddTrigger(
model_name='company',
trigger=pgtrigger.compiler.Trigger(name='update_update', sql=pgtrigger.compiler.UpsertTriggerSql(condition='WHEN (OLD.* IS DISTINCT FROM NEW.*)', func='INSERT INTO "rides_companyevent" ("banner_image_id", "card_image_id", "coasters_count", "created_at", "description", "founded_date", "founded_date_precision", "founded_year", "headquarters_location", "id", "location_id", "name", "person_type", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rides_count", "roles", "slug", "updated_at", "url", "website") VALUES (NEW."banner_image_id", NEW."card_image_id", NEW."coasters_count", NEW."created_at", NEW."description", NEW."founded_date", NEW."founded_date_precision", NEW."founded_year", NEW."headquarters_location", NEW."id", NEW."location_id", NEW."name", NEW."person_type", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."rides_count", NEW."roles", NEW."slug", NEW."updated_at", NEW."url", NEW."website"); RETURN NULL;', hash='d0c405cab0f8f61aa24dd2074fd615a56fcc812a', operation='UPDATE', pgid='pgtrigger_update_update_456a8', table='rides_company', when='AFTER')),
),
pgtrigger.migrations.AddTrigger(
model_name='ride',
trigger=pgtrigger.compiler.Trigger(name='insert_insert', sql=pgtrigger.compiler.UpsertTriggerSql(func='INSERT INTO "rides_rideevent" ("age_requirement", "animatronics_count", "arm_length_meters", "average_rating", "banner_image_id", "boat_capacity", "capacity_per_hour", "card_image_id", "category", "character_theme", "closing_date", "closing_date_precision", "coaster_type", "created_at", "description", "designer_id", "drop_meters", "duration_seconds", "educational_theme", "flume_type", "gforce_max", "height_meters", "height_requirement_cm", "id", "intensity_level", "inversions_count", "length_meters", "manufacturer_id", "max_age", "max_height_in", "max_height_reached_meters", "max_speed_kmh", "min_age", "min_height_in", "motion_pattern", "name", "opening_date", "opening_date_precision", "opening_year", "park_area_id", "park_id", "park_url", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "platform_count", "post_closing_status", "projection_type", "propulsion_method", "ride_duration_seconds", "ride_model_id", "ride_sub_type", "ride_system", "rotation_speed_rpm", "rotation_type", "round_trip_duration_seconds", "route_length_meters", "scenes_count", "search_text", "seating_type", "show_duration_seconds", "slug", "splash_height_meters", "stations_count", "status", "status_since", "story_description", "support_material", "swing_angle_degrees", "theme_name", "track_material", "transport_type", "updated_at", "url", "vehicle_capacity", "vehicles_count", "water_depth_cm", "wetness_level") VALUES (NEW."age_requirement", NEW."animatronics_count", NEW."arm_length_meters", NEW."average_rating", NEW."banner_image_id", NEW."boat_capacity", NEW."capacity_per_hour", NEW."card_image_id", NEW."category", NEW."character_theme", NEW."closing_date", NEW."closing_date_precision", NEW."coaster_type", NEW."created_at", NEW."description", NEW."designer_id", NEW."drop_meters", NEW."duration_seconds", NEW."educational_theme", NEW."flume_type", NEW."gforce_max", NEW."height_meters", NEW."height_requirement_cm", NEW."id", NEW."intensity_level", NEW."inversions_count", NEW."length_meters", NEW."manufacturer_id", NEW."max_age", NEW."max_height_in", NEW."max_height_reached_meters", NEW."max_speed_kmh", NEW."min_age", NEW."min_height_in", NEW."motion_pattern", NEW."name", NEW."opening_date", NEW."opening_date_precision", NEW."opening_year", NEW."park_area_id", NEW."park_id", NEW."park_url", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."platform_count", NEW."post_closing_status", NEW."projection_type", NEW."propulsion_method", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."ride_sub_type", NEW."ride_system", NEW."rotation_speed_rpm", NEW."rotation_type", NEW."round_trip_duration_seconds", NEW."route_length_meters", NEW."scenes_count", NEW."search_text", NEW."seating_type", NEW."show_duration_seconds", NEW."slug", NEW."splash_height_meters", NEW."stations_count", NEW."status", NEW."status_since", NEW."story_description", NEW."support_material", NEW."swing_angle_degrees", NEW."theme_name", NEW."track_material", NEW."transport_type", NEW."updated_at", NEW."url", NEW."vehicle_capacity", NEW."vehicles_count", NEW."water_depth_cm", NEW."wetness_level"); RETURN NULL;', hash='db6754d5334c498976180acdf6f2dd7c043cb9c1', operation='INSERT', pgid='pgtrigger_insert_insert_52074', table='rides_ride', when='AFTER')),
),
pgtrigger.migrations.AddTrigger(
model_name='ride',
trigger=pgtrigger.compiler.Trigger(name='update_update', sql=pgtrigger.compiler.UpsertTriggerSql(condition='WHEN (OLD.* IS DISTINCT FROM NEW.*)', func='INSERT INTO "rides_rideevent" ("age_requirement", "animatronics_count", "arm_length_meters", "average_rating", "banner_image_id", "boat_capacity", "capacity_per_hour", "card_image_id", "category", "character_theme", "closing_date", "closing_date_precision", "coaster_type", "created_at", "description", "designer_id", "drop_meters", "duration_seconds", "educational_theme", "flume_type", "gforce_max", "height_meters", "height_requirement_cm", "id", "intensity_level", "inversions_count", "length_meters", "manufacturer_id", "max_age", "max_height_in", "max_height_reached_meters", "max_speed_kmh", "min_age", "min_height_in", "motion_pattern", "name", "opening_date", "opening_date_precision", "opening_year", "park_area_id", "park_id", "park_url", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "platform_count", "post_closing_status", "projection_type", "propulsion_method", "ride_duration_seconds", "ride_model_id", "ride_sub_type", "ride_system", "rotation_speed_rpm", "rotation_type", "round_trip_duration_seconds", "route_length_meters", "scenes_count", "search_text", "seating_type", "show_duration_seconds", "slug", "splash_height_meters", "stations_count", "status", "status_since", "story_description", "support_material", "swing_angle_degrees", "theme_name", "track_material", "transport_type", "updated_at", "url", "vehicle_capacity", "vehicles_count", "water_depth_cm", "wetness_level") VALUES (NEW."age_requirement", NEW."animatronics_count", NEW."arm_length_meters", NEW."average_rating", NEW."banner_image_id", NEW."boat_capacity", NEW."capacity_per_hour", NEW."card_image_id", NEW."category", NEW."character_theme", NEW."closing_date", NEW."closing_date_precision", NEW."coaster_type", NEW."created_at", NEW."description", NEW."designer_id", NEW."drop_meters", NEW."duration_seconds", NEW."educational_theme", NEW."flume_type", NEW."gforce_max", NEW."height_meters", NEW."height_requirement_cm", NEW."id", NEW."intensity_level", NEW."inversions_count", NEW."length_meters", NEW."manufacturer_id", NEW."max_age", NEW."max_height_in", NEW."max_height_reached_meters", NEW."max_speed_kmh", NEW."min_age", NEW."min_height_in", NEW."motion_pattern", NEW."name", NEW."opening_date", NEW."opening_date_precision", NEW."opening_year", NEW."park_area_id", NEW."park_id", NEW."park_url", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."platform_count", NEW."post_closing_status", NEW."projection_type", NEW."propulsion_method", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."ride_sub_type", NEW."ride_system", NEW."rotation_speed_rpm", NEW."rotation_type", NEW."round_trip_duration_seconds", NEW."route_length_meters", NEW."scenes_count", NEW."search_text", NEW."seating_type", NEW."show_duration_seconds", NEW."slug", NEW."splash_height_meters", NEW."stations_count", NEW."status", NEW."status_since", NEW."story_description", NEW."support_material", NEW."swing_angle_degrees", NEW."theme_name", NEW."track_material", NEW."transport_type", NEW."updated_at", NEW."url", NEW."vehicle_capacity", NEW."vehicles_count", NEW."water_depth_cm", NEW."wetness_level"); RETURN NULL;', hash='3bff6632dbf5e5fab62671b5c2da263fb4682611', operation='UPDATE', pgid='pgtrigger_update_update_4917a', table='rides_ride', when='AFTER')),
),
]

View File

@@ -0,0 +1,107 @@
# Generated by Django 5.2.9 on 2026-01-08 18:05
import pgtrigger.compiler
import pgtrigger.migrations
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rides', '0036_add_remaining_parity_fields'),
]
operations = [
pgtrigger.migrations.RemoveTrigger(
model_name='ride',
name='insert_insert',
),
pgtrigger.migrations.RemoveTrigger(
model_name='ride',
name='update_update',
),
pgtrigger.migrations.RemoveTrigger(
model_name='ridemodel',
name='insert_insert',
),
pgtrigger.migrations.RemoveTrigger(
model_name='ridemodel',
name='update_update',
),
migrations.AddField(
model_name='ride',
name='is_test_data',
field=models.BooleanField(default=False, help_text='Whether this is test/development data'),
),
migrations.AddField(
model_name='ride',
name='source_url',
field=models.URLField(blank=True, help_text='Source URL for the data (e.g., official website, RCDB)'),
),
migrations.AddField(
model_name='rideevent',
name='is_test_data',
field=models.BooleanField(default=False, help_text='Whether this is test/development data'),
),
migrations.AddField(
model_name='rideevent',
name='source_url',
field=models.URLField(blank=True, help_text='Source URL for the data (e.g., official website, RCDB)'),
),
migrations.AddField(
model_name='ridemodel',
name='is_test_data',
field=models.BooleanField(default=False, help_text='Whether this is test/development data'),
),
migrations.AddField(
model_name='ridemodel',
name='source_url',
field=models.URLField(blank=True, help_text='Source URL for the data (e.g., manufacturer website)'),
),
migrations.AddField(
model_name='ridemodelevent',
name='is_test_data',
field=models.BooleanField(default=False, help_text='Whether this is test/development data'),
),
migrations.AddField(
model_name='ridemodelevent',
name='source_url',
field=models.URLField(blank=True, help_text='Source URL for the data (e.g., manufacturer website)'),
),
migrations.AlterField(
model_name='ride',
name='closing_date_precision',
field=models.CharField(blank=True, choices=[('exact', 'Exact Date'), ('month', 'Month and Year'), ('year', 'Year Only'), ('decade', 'Decade'), ('century', 'Century'), ('approximate', 'Approximate')], default='exact', help_text='Precision of the closing date', max_length=20),
),
migrations.AlterField(
model_name='ride',
name='opening_date_precision',
field=models.CharField(blank=True, choices=[('exact', 'Exact Date'), ('month', 'Month and Year'), ('year', 'Year Only'), ('decade', 'Decade'), ('century', 'Century'), ('approximate', 'Approximate')], default='exact', help_text='Precision of the opening date', max_length=20),
),
migrations.AlterField(
model_name='rideevent',
name='closing_date_precision',
field=models.CharField(blank=True, choices=[('exact', 'Exact Date'), ('month', 'Month and Year'), ('year', 'Year Only'), ('decade', 'Decade'), ('century', 'Century'), ('approximate', 'Approximate')], default='exact', help_text='Precision of the closing date', max_length=20),
),
migrations.AlterField(
model_name='rideevent',
name='opening_date_precision',
field=models.CharField(blank=True, choices=[('exact', 'Exact Date'), ('month', 'Month and Year'), ('year', 'Year Only'), ('decade', 'Decade'), ('century', 'Century'), ('approximate', 'Approximate')], default='exact', help_text='Precision of the opening date', max_length=20),
),
pgtrigger.migrations.AddTrigger(
model_name='ride',
trigger=pgtrigger.compiler.Trigger(name='insert_insert', sql=pgtrigger.compiler.UpsertTriggerSql(func='INSERT INTO "rides_rideevent" ("age_requirement", "animatronics_count", "arm_length_meters", "average_rating", "banner_image_id", "boat_capacity", "capacity_per_hour", "card_image_id", "category", "character_theme", "closing_date", "closing_date_precision", "coaster_type", "created_at", "description", "designer_id", "drop_meters", "duration_seconds", "educational_theme", "flume_type", "gforce_max", "height_meters", "height_requirement_cm", "id", "intensity_level", "inversions_count", "is_test_data", "length_meters", "manufacturer_id", "max_age", "max_height_in", "max_height_reached_meters", "max_speed_kmh", "min_age", "min_height_in", "motion_pattern", "name", "opening_date", "opening_date_precision", "opening_year", "park_area_id", "park_id", "park_url", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "platform_count", "post_closing_status", "projection_type", "propulsion_method", "ride_duration_seconds", "ride_model_id", "ride_sub_type", "ride_system", "rotation_speed_rpm", "rotation_type", "round_trip_duration_seconds", "route_length_meters", "scenes_count", "search_text", "seating_type", "show_duration_seconds", "slug", "source_url", "splash_height_meters", "stations_count", "status", "status_since", "story_description", "support_material", "swing_angle_degrees", "theme_name", "track_material", "transport_type", "updated_at", "url", "vehicle_capacity", "vehicles_count", "water_depth_cm", "wetness_level") VALUES (NEW."age_requirement", NEW."animatronics_count", NEW."arm_length_meters", NEW."average_rating", NEW."banner_image_id", NEW."boat_capacity", NEW."capacity_per_hour", NEW."card_image_id", NEW."category", NEW."character_theme", NEW."closing_date", NEW."closing_date_precision", NEW."coaster_type", NEW."created_at", NEW."description", NEW."designer_id", NEW."drop_meters", NEW."duration_seconds", NEW."educational_theme", NEW."flume_type", NEW."gforce_max", NEW."height_meters", NEW."height_requirement_cm", NEW."id", NEW."intensity_level", NEW."inversions_count", NEW."is_test_data", NEW."length_meters", NEW."manufacturer_id", NEW."max_age", NEW."max_height_in", NEW."max_height_reached_meters", NEW."max_speed_kmh", NEW."min_age", NEW."min_height_in", NEW."motion_pattern", NEW."name", NEW."opening_date", NEW."opening_date_precision", NEW."opening_year", NEW."park_area_id", NEW."park_id", NEW."park_url", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."platform_count", NEW."post_closing_status", NEW."projection_type", NEW."propulsion_method", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."ride_sub_type", NEW."ride_system", NEW."rotation_speed_rpm", NEW."rotation_type", NEW."round_trip_duration_seconds", NEW."route_length_meters", NEW."scenes_count", NEW."search_text", NEW."seating_type", NEW."show_duration_seconds", NEW."slug", NEW."source_url", NEW."splash_height_meters", NEW."stations_count", NEW."status", NEW."status_since", NEW."story_description", NEW."support_material", NEW."swing_angle_degrees", NEW."theme_name", NEW."track_material", NEW."transport_type", NEW."updated_at", NEW."url", NEW."vehicle_capacity", NEW."vehicles_count", NEW."water_depth_cm", NEW."wetness_level"); RETURN NULL;', hash='07c5cf95d16c49e08014c23a4e5e35f55292c869', operation='INSERT', pgid='pgtrigger_insert_insert_52074', table='rides_ride', when='AFTER')),
),
pgtrigger.migrations.AddTrigger(
model_name='ride',
trigger=pgtrigger.compiler.Trigger(name='update_update', sql=pgtrigger.compiler.UpsertTriggerSql(condition='WHEN (OLD.* IS DISTINCT FROM NEW.*)', func='INSERT INTO "rides_rideevent" ("age_requirement", "animatronics_count", "arm_length_meters", "average_rating", "banner_image_id", "boat_capacity", "capacity_per_hour", "card_image_id", "category", "character_theme", "closing_date", "closing_date_precision", "coaster_type", "created_at", "description", "designer_id", "drop_meters", "duration_seconds", "educational_theme", "flume_type", "gforce_max", "height_meters", "height_requirement_cm", "id", "intensity_level", "inversions_count", "is_test_data", "length_meters", "manufacturer_id", "max_age", "max_height_in", "max_height_reached_meters", "max_speed_kmh", "min_age", "min_height_in", "motion_pattern", "name", "opening_date", "opening_date_precision", "opening_year", "park_area_id", "park_id", "park_url", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "platform_count", "post_closing_status", "projection_type", "propulsion_method", "ride_duration_seconds", "ride_model_id", "ride_sub_type", "ride_system", "rotation_speed_rpm", "rotation_type", "round_trip_duration_seconds", "route_length_meters", "scenes_count", "search_text", "seating_type", "show_duration_seconds", "slug", "source_url", "splash_height_meters", "stations_count", "status", "status_since", "story_description", "support_material", "swing_angle_degrees", "theme_name", "track_material", "transport_type", "updated_at", "url", "vehicle_capacity", "vehicles_count", "water_depth_cm", "wetness_level") VALUES (NEW."age_requirement", NEW."animatronics_count", NEW."arm_length_meters", NEW."average_rating", NEW."banner_image_id", NEW."boat_capacity", NEW."capacity_per_hour", NEW."card_image_id", NEW."category", NEW."character_theme", NEW."closing_date", NEW."closing_date_precision", NEW."coaster_type", NEW."created_at", NEW."description", NEW."designer_id", NEW."drop_meters", NEW."duration_seconds", NEW."educational_theme", NEW."flume_type", NEW."gforce_max", NEW."height_meters", NEW."height_requirement_cm", NEW."id", NEW."intensity_level", NEW."inversions_count", NEW."is_test_data", NEW."length_meters", NEW."manufacturer_id", NEW."max_age", NEW."max_height_in", NEW."max_height_reached_meters", NEW."max_speed_kmh", NEW."min_age", NEW."min_height_in", NEW."motion_pattern", NEW."name", NEW."opening_date", NEW."opening_date_precision", NEW."opening_year", NEW."park_area_id", NEW."park_id", NEW."park_url", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."platform_count", NEW."post_closing_status", NEW."projection_type", NEW."propulsion_method", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."ride_sub_type", NEW."ride_system", NEW."rotation_speed_rpm", NEW."rotation_type", NEW."round_trip_duration_seconds", NEW."route_length_meters", NEW."scenes_count", NEW."search_text", NEW."seating_type", NEW."show_duration_seconds", NEW."slug", NEW."source_url", NEW."splash_height_meters", NEW."stations_count", NEW."status", NEW."status_since", NEW."story_description", NEW."support_material", NEW."swing_angle_degrees", NEW."theme_name", NEW."track_material", NEW."transport_type", NEW."updated_at", NEW."url", NEW."vehicle_capacity", NEW."vehicles_count", NEW."water_depth_cm", NEW."wetness_level"); RETURN NULL;', hash='dabf771ba40b71c4d91ad1b1ed97a9712578096c', operation='UPDATE', pgid='pgtrigger_update_update_4917a', table='rides_ride', when='AFTER')),
),
pgtrigger.migrations.AddTrigger(
model_name='ridemodel',
trigger=pgtrigger.compiler.Trigger(name='insert_insert', sql=pgtrigger.compiler.UpsertTriggerSql(func='INSERT INTO "rides_ridemodelevent" ("category", "created_at", "description", "first_installation_year", "id", "is_discontinued", "is_test_data", "last_installation_year", "manufacturer_id", "meta_description", "meta_title", "name", "notable_features", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "primary_image_id", "restraint_system", "ride_type", "slug", "source_url", "support_structure", "target_market", "total_installations", "track_type", "train_configuration", "typical_capacity_range_max", "typical_capacity_range_min", "typical_height_range_max_ft", "typical_height_range_min_ft", "typical_speed_range_max_mph", "typical_speed_range_min_mph", "updated_at", "url") VALUES (NEW."category", NEW."created_at", NEW."description", NEW."first_installation_year", NEW."id", NEW."is_discontinued", NEW."is_test_data", NEW."last_installation_year", NEW."manufacturer_id", NEW."meta_description", NEW."meta_title", NEW."name", NEW."notable_features", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."primary_image_id", NEW."restraint_system", NEW."ride_type", NEW."slug", NEW."source_url", NEW."support_structure", NEW."target_market", NEW."total_installations", NEW."track_type", NEW."train_configuration", NEW."typical_capacity_range_max", NEW."typical_capacity_range_min", NEW."typical_height_range_max_ft", NEW."typical_height_range_min_ft", NEW."typical_speed_range_max_mph", NEW."typical_speed_range_min_mph", NEW."updated_at", NEW."url"); RETURN NULL;', hash='9cc07f0217f79924bae066b5b8f9e7d5f55e211c', operation='INSERT', pgid='pgtrigger_insert_insert_0aaee', table='rides_ridemodel', when='AFTER')),
),
pgtrigger.migrations.AddTrigger(
model_name='ridemodel',
trigger=pgtrigger.compiler.Trigger(name='update_update', sql=pgtrigger.compiler.UpsertTriggerSql(condition='WHEN (OLD.* IS DISTINCT FROM NEW.*)', func='INSERT INTO "rides_ridemodelevent" ("category", "created_at", "description", "first_installation_year", "id", "is_discontinued", "is_test_data", "last_installation_year", "manufacturer_id", "meta_description", "meta_title", "name", "notable_features", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "primary_image_id", "restraint_system", "ride_type", "slug", "source_url", "support_structure", "target_market", "total_installations", "track_type", "train_configuration", "typical_capacity_range_max", "typical_capacity_range_min", "typical_height_range_max_ft", "typical_height_range_min_ft", "typical_speed_range_max_mph", "typical_speed_range_min_mph", "updated_at", "url") VALUES (NEW."category", NEW."created_at", NEW."description", NEW."first_installation_year", NEW."id", NEW."is_discontinued", NEW."is_test_data", NEW."last_installation_year", NEW."manufacturer_id", NEW."meta_description", NEW."meta_title", NEW."name", NEW."notable_features", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."primary_image_id", NEW."restraint_system", NEW."ride_type", NEW."slug", NEW."source_url", NEW."support_structure", NEW."target_market", NEW."total_installations", NEW."track_type", NEW."train_configuration", NEW."typical_capacity_range_max", NEW."typical_capacity_range_min", NEW."typical_height_range_max_ft", NEW."typical_height_range_min_ft", NEW."typical_speed_range_max_mph", NEW."typical_speed_range_min_mph", NEW."updated_at", NEW."url"); RETURN NULL;', hash='f9f826a678fc0ed93ab788206fdb724c5445e469', operation='UPDATE', pgid='pgtrigger_update_update_0ca1a', table='rides_ridemodel', when='AFTER')),
),
]

View File

@@ -0,0 +1,51 @@
# Generated by Django 5.2.9 on 2026-01-08 18:20
import pgtrigger.compiler
import pgtrigger.migrations
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rides', '0037_add_source_url_is_test_data_and_date_precision'),
]
operations = [
pgtrigger.migrations.RemoveTrigger(
model_name='company',
name='insert_insert',
),
pgtrigger.migrations.RemoveTrigger(
model_name='company',
name='update_update',
),
migrations.AddField(
model_name='company',
name='is_test_data',
field=models.BooleanField(default=False, help_text='Whether this is test/development data'),
),
migrations.AddField(
model_name='company',
name='source_url',
field=models.URLField(blank=True, help_text='Source URL for the data (e.g., official website, Wikipedia)'),
),
migrations.AddField(
model_name='companyevent',
name='is_test_data',
field=models.BooleanField(default=False, help_text='Whether this is test/development data'),
),
migrations.AddField(
model_name='companyevent',
name='source_url',
field=models.URLField(blank=True, help_text='Source URL for the data (e.g., official website, Wikipedia)'),
),
pgtrigger.migrations.AddTrigger(
model_name='company',
trigger=pgtrigger.compiler.Trigger(name='insert_insert', sql=pgtrigger.compiler.UpsertTriggerSql(func='INSERT INTO "rides_companyevent" ("banner_image_id", "card_image_id", "coasters_count", "created_at", "description", "founded_date", "founded_date_precision", "founded_year", "headquarters_location", "id", "is_test_data", "location_id", "name", "person_type", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rides_count", "roles", "slug", "source_url", "updated_at", "url", "website") VALUES (NEW."banner_image_id", NEW."card_image_id", NEW."coasters_count", NEW."created_at", NEW."description", NEW."founded_date", NEW."founded_date_precision", NEW."founded_year", NEW."headquarters_location", NEW."id", NEW."is_test_data", NEW."location_id", NEW."name", NEW."person_type", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."rides_count", NEW."roles", NEW."slug", NEW."source_url", NEW."updated_at", NEW."url", NEW."website"); RETURN NULL;', hash='26c30b4bcabc0661de7627f32a6b12d2ea9895ac', operation='INSERT', pgid='pgtrigger_insert_insert_e7194', table='rides_company', when='AFTER')),
),
pgtrigger.migrations.AddTrigger(
model_name='company',
trigger=pgtrigger.compiler.Trigger(name='update_update', sql=pgtrigger.compiler.UpsertTriggerSql(condition='WHEN (OLD.* IS DISTINCT FROM NEW.*)', func='INSERT INTO "rides_companyevent" ("banner_image_id", "card_image_id", "coasters_count", "created_at", "description", "founded_date", "founded_date_precision", "founded_year", "headquarters_location", "id", "is_test_data", "location_id", "name", "person_type", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rides_count", "roles", "slug", "source_url", "updated_at", "url", "website") VALUES (NEW."banner_image_id", NEW."card_image_id", NEW."coasters_count", NEW."created_at", NEW."description", NEW."founded_date", NEW."founded_date_precision", NEW."founded_year", NEW."headquarters_location", NEW."id", NEW."is_test_data", NEW."location_id", NEW."name", NEW."person_type", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."rides_count", NEW."roles", NEW."slug", NEW."source_url", NEW."updated_at", NEW."url", NEW."website"); RETURN NULL;', hash='211e480aa3391c67288564ec1fdfa2552956bbba', operation='UPDATE', pgid='pgtrigger_update_update_456a8', table='rides_company', when='AFTER')),
),
]

View File

@@ -22,9 +22,70 @@ class Company(TrackedModel):
)
description = models.TextField(blank=True, help_text="Detailed company description")
website = models.URLField(blank=True, help_text="Company website URL")
# Person/Entity type
PERSON_TYPE_CHOICES = [
("company", "Company"),
("individual", "Individual"),
("firm", "Firm"),
("organization", "Organization"),
]
person_type = models.CharField(
max_length=20,
choices=PERSON_TYPE_CHOICES,
blank=True,
default="company",
help_text="Type of entity (company, individual, firm, organization)",
)
# General company info
founded_date = models.DateField(null=True, blank=True, help_text="Date the company was founded")
founded_date_precision = models.CharField(
max_length=20,
choices=[
("exact", "Exact"),
("month", "Month"),
("year", "Year"),
("decade", "Decade"),
("century", "Century"),
("approximate", "Approximate"),
],
blank=True,
default="",
help_text="Precision of the founded date",
)
founded_year = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Year the company was founded (alternative to founded_date)",
)
headquarters_location = models.CharField(
max_length=200,
blank=True,
help_text="Headquarters location description (e.g., 'Los Angeles, CA, USA')",
)
# Location relationship (optional)
location = models.ForeignKey(
"parks.ParkLocation",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="companies",
help_text="Linked location record for headquarters",
)
# Image settings - stored as Cloudflare image IDs/URLs
banner_image_id = models.CharField(
max_length=255,
blank=True,
help_text="Cloudflare image ID for banner image",
)
card_image_id = models.CharField(
max_length=255,
blank=True,
help_text="Cloudflare image ID for card image",
)
# Manufacturer-specific fields
rides_count = models.IntegerField(default=0, help_text="Number of rides manufactured (auto-calculated)")
@@ -33,6 +94,16 @@ class Company(TrackedModel):
# Frontend URL
url = models.URLField(blank=True, help_text="Frontend URL for this company")
# Submission metadata fields (from frontend schema)
source_url = models.URLField(
blank=True,
help_text="Source URL for the data (e.g., official website, Wikipedia)",
)
is_test_data = models.BooleanField(
default=False,
help_text="Whether this is test/development data",
)
def __str__(self):
return self.name

View File

@@ -2,6 +2,7 @@ import contextlib
import pghistory
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.postgres.fields import ArrayField
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.text import slugify
@@ -44,6 +45,11 @@ class RideModel(TrackedModel):
blank=True,
help_text="Primary category classification",
)
ride_type = models.CharField(
max_length=100,
blank=True,
help_text="Specific ride type within the category (e.g., 'Flying Coaster', 'Inverted Coaster')",
)
# Technical specifications
typical_height_range_min_ft = models.DecimalField(
@@ -155,6 +161,16 @@ class RideModel(TrackedModel):
# Frontend URL
url = models.URLField(blank=True, help_text="Frontend URL for this ride model")
# Submission metadata fields (from frontend schema)
source_url = models.URLField(
blank=True,
help_text="Source URL for the data (e.g., manufacturer website)",
)
is_test_data = models.BooleanField(
default=False,
help_text="Whether this is test/development data",
)
class Meta(TrackedModel.Meta):
verbose_name = "Ride Model"
verbose_name_plural = "Ride Models"
@@ -509,17 +525,31 @@ class Ride(StateMachineMixin, TrackedModel):
)
opening_date = models.DateField(null=True, blank=True)
opening_date_precision = models.CharField(
max_length=10,
choices=[("YEAR", "Year"), ("MONTH", "Month"), ("DAY", "Day")],
default="DAY",
max_length=20,
choices=[
("exact", "Exact Date"),
("month", "Month and Year"),
("year", "Year Only"),
("decade", "Decade"),
("century", "Century"),
("approximate", "Approximate"),
],
default="exact",
blank=True,
help_text="Precision of the opening date",
)
closing_date = models.DateField(null=True, blank=True)
closing_date_precision = models.CharField(
max_length=10,
choices=[("YEAR", "Year"), ("MONTH", "Month"), ("DAY", "Day")],
default="DAY",
max_length=20,
choices=[
("exact", "Exact Date"),
("month", "Month and Year"),
("year", "Year Only"),
("decade", "Decade"),
("century", "Century"),
("approximate", "Approximate"),
],
default="exact",
blank=True,
help_text="Precision of the closing date",
)
@@ -541,11 +571,268 @@ class Ride(StateMachineMixin, TrackedModel):
blank=True,
help_text="Minimum age requirement in years (if any)",
)
height_requirement_cm = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Minimum height requirement in centimeters",
)
duration_seconds = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Ride duration in seconds",
)
inversions_count = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Number of inversions (for coasters)",
)
# Computed fields for hybrid filtering
opening_year = models.IntegerField(null=True, blank=True, db_index=True)
search_text = models.TextField(blank=True, db_index=True)
# ===== CATEGORY-SPECIFIC FIELDS =====
# These fields support the frontend validation schemas in entityValidationSchemas.ts
# Fields are nullable since they only apply to specific ride categories
# --- Core Stats (6 fields) ---
max_speed_kmh = models.DecimalField(
max_digits=6,
decimal_places=2,
null=True,
blank=True,
help_text="Maximum speed in kilometers per hour",
)
height_meters = models.DecimalField(
max_digits=6,
decimal_places=2,
null=True,
blank=True,
help_text="Height of the ride structure in meters",
)
length_meters = models.DecimalField(
max_digits=8,
decimal_places=2,
null=True,
blank=True,
help_text="Total track/ride length in meters",
)
drop_meters = models.DecimalField(
max_digits=6,
decimal_places=2,
null=True,
blank=True,
help_text="Maximum drop height in meters",
)
gforce_max = models.DecimalField(
max_digits=4,
decimal_places=2,
null=True,
blank=True,
help_text="Maximum G-force experienced",
)
intensity_level = models.CharField(
max_length=20,
blank=True,
help_text="Intensity classification: family, thrill, or extreme",
)
# --- Coaster-Specific (5 fields) ---
coaster_type = models.CharField(
max_length=20,
blank=True,
help_text="Coaster structure type: steel, wood, or hybrid",
)
seating_type = models.CharField(
max_length=20,
blank=True,
help_text="Seating configuration: sit_down, inverted, flying, stand_up, etc.",
)
track_material = ArrayField(
models.CharField(max_length=50),
blank=True,
default=list,
help_text="Track material types (e.g., ['steel', 'wood'])",
)
support_material = ArrayField(
models.CharField(max_length=50),
blank=True,
default=list,
help_text="Support structure material types",
)
propulsion_method = ArrayField(
models.CharField(max_length=50),
blank=True,
default=list,
help_text="Propulsion methods (e.g., ['chain_lift', 'lsm'])",
)
# --- Water Ride (5 fields) ---
water_depth_cm = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Water depth in centimeters",
)
splash_height_meters = models.DecimalField(
max_digits=5,
decimal_places=2,
null=True,
blank=True,
help_text="Maximum splash height in meters",
)
wetness_level = models.CharField(
max_length=20,
blank=True,
help_text="Expected wetness: dry, light, moderate, or soaked",
)
flume_type = models.CharField(
max_length=100,
blank=True,
help_text="Type of flume or water channel",
)
boat_capacity = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Number of passengers per boat/vehicle",
)
# --- Dark Ride (7 fields) ---
theme_name = models.CharField(
max_length=200,
blank=True,
help_text="Primary theme or IP name",
)
story_description = models.TextField(
blank=True,
help_text="Narrative or story description for the ride",
)
show_duration_seconds = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Duration of show elements in seconds",
)
animatronics_count = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Number of animatronic figures",
)
projection_type = models.CharField(
max_length=100,
blank=True,
help_text="Type of projection technology used",
)
ride_system = models.CharField(
max_length=100,
blank=True,
help_text="Ride system type (e.g., trackless, omnimover)",
)
scenes_count = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Number of distinct scenes or show sections",
)
# --- Flat Ride (7 fields) ---
rotation_type = models.CharField(
max_length=20,
blank=True,
help_text="Rotation axis: horizontal, vertical, multi_axis, pendulum, or none",
)
motion_pattern = models.CharField(
max_length=200,
blank=True,
help_text="Description of the ride's motion pattern",
)
platform_count = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Number of ride platforms or gondolas",
)
swing_angle_degrees = models.DecimalField(
max_digits=5,
decimal_places=2,
null=True,
blank=True,
help_text="Maximum swing angle in degrees",
)
rotation_speed_rpm = models.DecimalField(
max_digits=6,
decimal_places=2,
null=True,
blank=True,
help_text="Rotation speed in revolutions per minute",
)
arm_length_meters = models.DecimalField(
max_digits=5,
decimal_places=2,
null=True,
blank=True,
help_text="Length of ride arm in meters",
)
max_height_reached_meters = models.DecimalField(
max_digits=6,
decimal_places=2,
null=True,
blank=True,
help_text="Maximum height reached during ride cycle in meters",
)
# --- Kiddie Ride (4 fields) ---
min_age = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Minimum recommended age in years",
)
max_age = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Maximum recommended age in years",
)
educational_theme = models.CharField(
max_length=200,
blank=True,
help_text="Educational or learning theme if applicable",
)
character_theme = models.CharField(
max_length=200,
blank=True,
help_text="Character or IP theme (e.g., Paw Patrol, Sesame Street)",
)
# --- Transportation (6 fields) ---
transport_type = models.CharField(
max_length=20,
blank=True,
help_text="Transport mode: train, monorail, skylift, ferry, peoplemover, or cable_car",
)
route_length_meters = models.DecimalField(
max_digits=8,
decimal_places=2,
null=True,
blank=True,
help_text="Total route length in meters",
)
stations_count = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Number of stations or stops",
)
vehicle_capacity = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Passenger capacity per vehicle",
)
vehicles_count = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Number of vehicles in operation",
)
round_trip_duration_seconds = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Duration of a complete round trip in seconds",
)
# Image settings - references to existing photos
banner_image = models.ForeignKey(
"RidePhoto",
@@ -568,6 +855,16 @@ class Ride(StateMachineMixin, TrackedModel):
url = models.URLField(blank=True, help_text="Frontend URL for this ride")
park_url = models.URLField(blank=True, help_text="Frontend URL for this ride's park")
# Submission metadata fields (from frontend schema)
source_url = models.URLField(
blank=True,
help_text="Source URL for the data (e.g., official website, RCDB)",
)
is_test_data = models.BooleanField(
default=False,
help_text="Whether this is test/development data",
)
class Meta(TrackedModel.Meta):
verbose_name = "Ride"
verbose_name_plural = "Rides"

View File

@@ -209,7 +209,7 @@ def update_ride_search_text_on_park_change(sender, instance, **kwargs):
logger.exception(f"Failed to update ride search_text on park change: {e}")
@receiver(post_save, sender="parks.Company")
@receiver(post_save, sender="rides.Company")
def update_ride_search_text_on_company_change(sender, instance, **kwargs):
"""
Update ride search_text when manufacturer/designer name changes.

View File

@@ -30,14 +30,14 @@ class RideOpeningWorkflowTests(TestCase):
def _create_ride(self, status="OPERATING", **kwargs):
"""Helper to create a ride with park."""
from apps.parks.models import Company, Park
from apps.rides.models import Ride
from apps.parks.models import Company as ParkCompany, Park
from apps.rides.models import Company as RideCompany, Ride
# Create manufacturer
manufacturer = Company.objects.create(name=f"Manufacturer {timezone.now().timestamp()}", roles=["MANUFACTURER"])
# Create manufacturer (from rides.Company)
manufacturer = RideCompany.objects.create(name=f"Manufacturer {timezone.now().timestamp()}", roles=["MANUFACTURER"])
# Create park with operator
operator = Company.objects.create(name=f"Operator {timezone.now().timestamp()}", roles=["OPERATOR"])
# Create park with operator (from parks.Company)
operator = ParkCompany.objects.create(name=f"Operator {timezone.now().timestamp()}", roles=["OPERATOR"])
park = Park.objects.create(
name=f"Test Park {timezone.now().timestamp()}",
slug=f"test-park-{timezone.now().timestamp()}",
@@ -84,11 +84,11 @@ class RideMaintenanceWorkflowTests(TestCase):
)
def _create_ride(self, status="OPERATING", **kwargs):
from apps.parks.models import Company, Park
from apps.rides.models import Ride
from apps.parks.models import Company as ParkCompany, Park
from apps.rides.models import Company as RideCompany, Ride
manufacturer = Company.objects.create(name=f"Mfr Maint {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = Company.objects.create(name=f"Op Maint {timezone.now().timestamp()}", roles=["OPERATOR"])
manufacturer = RideCompany.objects.create(name=f"Mfr Maint {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = ParkCompany.objects.create(name=f"Op Maint {timezone.now().timestamp()}", roles=["OPERATOR"])
park = Park.objects.create(
name=f"Park Maint {timezone.now().timestamp()}",
slug=f"park-maint-{timezone.now().timestamp()}",
@@ -140,11 +140,11 @@ class RideSBNOWorkflowTests(TestCase):
)
def _create_ride(self, status="OPERATING", **kwargs):
from apps.parks.models import Company, Park
from apps.rides.models import Ride
from apps.parks.models import Company as ParkCompany, Park
from apps.rides.models import Company as RideCompany, Ride
manufacturer = Company.objects.create(name=f"Mfr SBNO {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = Company.objects.create(name=f"Op SBNO {timezone.now().timestamp()}", roles=["OPERATOR"])
manufacturer = RideCompany.objects.create(name=f"Mfr SBNO {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = ParkCompany.objects.create(name=f"Op SBNO {timezone.now().timestamp()}", roles=["OPERATOR"])
park = Park.objects.create(
name=f"Park SBNO {timezone.now().timestamp()}",
slug=f"park-sbno-{timezone.now().timestamp()}",
@@ -234,11 +234,11 @@ class RideScheduledClosureWorkflowTests(TestCase):
)
def _create_ride(self, status="OPERATING", **kwargs):
from apps.parks.models import Company, Park
from apps.rides.models import Ride
from apps.parks.models import Company as ParkCompany, Park
from apps.rides.models import Company as RideCompany, Ride
manufacturer = Company.objects.create(name=f"Mfr Closing {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = Company.objects.create(name=f"Op Closing {timezone.now().timestamp()}", roles=["OPERATOR"])
manufacturer = RideCompany.objects.create(name=f"Mfr Closing {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = ParkCompany.objects.create(name=f"Op Closing {timezone.now().timestamp()}", roles=["OPERATOR"])
park = Park.objects.create(
name=f"Park Closing {timezone.now().timestamp()}",
slug=f"park-closing-{timezone.now().timestamp()}",
@@ -324,11 +324,11 @@ class RideDemolitionWorkflowTests(TestCase):
)
def _create_ride(self, status="CLOSED_PERM", **kwargs):
from apps.parks.models import Company, Park
from apps.rides.models import Ride
from apps.parks.models import Company as ParkCompany, Park
from apps.rides.models import Company as RideCompany, Ride
manufacturer = Company.objects.create(name=f"Mfr Demo {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = Company.objects.create(name=f"Op Demo {timezone.now().timestamp()}", roles=["OPERATOR"])
manufacturer = RideCompany.objects.create(name=f"Mfr Demo {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = ParkCompany.objects.create(name=f"Op Demo {timezone.now().timestamp()}", roles=["OPERATOR"])
park = Park.objects.create(
name=f"Park Demo {timezone.now().timestamp()}",
slug=f"park-demo-{timezone.now().timestamp()}",
@@ -383,11 +383,11 @@ class RideRelocationWorkflowTests(TestCase):
)
def _create_ride(self, status="CLOSED_PERM", **kwargs):
from apps.parks.models import Company, Park
from apps.rides.models import Ride
from apps.parks.models import Company as ParkCompany, Park
from apps.rides.models import Company as RideCompany, Ride
manufacturer = Company.objects.create(name=f"Mfr Reloc {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = Company.objects.create(name=f"Op Reloc {timezone.now().timestamp()}", roles=["OPERATOR"])
manufacturer = RideCompany.objects.create(name=f"Mfr Reloc {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = ParkCompany.objects.create(name=f"Op Reloc {timezone.now().timestamp()}", roles=["OPERATOR"])
park = Park.objects.create(
name=f"Park Reloc {timezone.now().timestamp()}",
slug=f"park-reloc-{timezone.now().timestamp()}",
@@ -445,11 +445,11 @@ class RideWrapperMethodTests(TestCase):
)
def _create_ride(self, status="OPERATING", **kwargs):
from apps.parks.models import Company, Park
from apps.rides.models import Ride
from apps.parks.models import Company as ParkCompany, Park
from apps.rides.models import Company as RideCompany, Ride
manufacturer = Company.objects.create(name=f"Mfr Wrapper {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = Company.objects.create(name=f"Op Wrapper {timezone.now().timestamp()}", roles=["OPERATOR"])
manufacturer = RideCompany.objects.create(name=f"Mfr Wrapper {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = ParkCompany.objects.create(name=f"Op Wrapper {timezone.now().timestamp()}", roles=["OPERATOR"])
park = Park.objects.create(
name=f"Park Wrapper {timezone.now().timestamp()}",
slug=f"park-wrapper-{timezone.now().timestamp()}",
@@ -573,11 +573,11 @@ class RidePostClosingStatusAutomationTests(TestCase):
)
def _create_ride(self, status="CLOSING", **kwargs):
from apps.parks.models import Company, Park
from apps.rides.models import Ride
from apps.parks.models import Company as ParkCompany, Park
from apps.rides.models import Company as RideCompany, Ride
manufacturer = Company.objects.create(name=f"Mfr Auto {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = Company.objects.create(name=f"Op Auto {timezone.now().timestamp()}", roles=["OPERATOR"])
manufacturer = RideCompany.objects.create(name=f"Mfr Auto {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = ParkCompany.objects.create(name=f"Op Auto {timezone.now().timestamp()}", roles=["OPERATOR"])
park = Park.objects.create(
name=f"Park Auto {timezone.now().timestamp()}",
slug=f"park-auto-{timezone.now().timestamp()}",
@@ -659,11 +659,11 @@ class RideStateLogTests(TestCase):
)
def _create_ride(self, status="OPERATING", **kwargs):
from apps.parks.models import Company, Park
from apps.rides.models import Ride
from apps.parks.models import Company as ParkCompany, Park
from apps.rides.models import Company as RideCompany, Ride
manufacturer = Company.objects.create(name=f"Mfr Log {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = Company.objects.create(name=f"Op Log {timezone.now().timestamp()}", roles=["OPERATOR"])
manufacturer = RideCompany.objects.create(name=f"Mfr Log {timezone.now().timestamp()}", roles=["MANUFACTURER"])
operator = ParkCompany.objects.create(name=f"Op Log {timezone.now().timestamp()}", roles=["OPERATOR"])
park = Park.objects.create(
name=f"Park Log {timezone.now().timestamp()}",
slug=f"park-log-{timezone.now().timestamp()}",