mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-30 08:27:00 -05:00
feat: Implement MFA authentication, add ride statistics model, and update various services, APIs, and tests across the application.
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
# Generated by Django 5.2.5 on 2025-08-26 17:39
|
||||
|
||||
import apps.rides.models.media
|
||||
import django.db.models.deletion
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
import apps.rides.models.media
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
|
||||
@@ -6,36 +6,36 @@ in the previous migration. These fields enable efficient hybrid filtering by
|
||||
pre-computing commonly filtered and searched data.
|
||||
"""
|
||||
|
||||
from django.db import migrations
|
||||
import pghistory
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def populate_computed_fields(apps, schema_editor):
|
||||
"""Populate computed fields for all existing rides."""
|
||||
Ride = apps.get_model('rides', 'Ride')
|
||||
|
||||
|
||||
# Disable pghistory triggers during bulk operations to avoid performance issues
|
||||
with pghistory.context(disable=True):
|
||||
rides = list(Ride.objects.all().select_related(
|
||||
'park', 'park__location', 'park_area', 'manufacturer', 'designer', 'ride_model'
|
||||
))
|
||||
|
||||
|
||||
for ride in rides:
|
||||
# Extract opening year from opening_date
|
||||
if ride.opening_date:
|
||||
ride.opening_year = ride.opening_date.year
|
||||
else:
|
||||
ride.opening_year = None
|
||||
|
||||
|
||||
# Build comprehensive search text
|
||||
search_parts = []
|
||||
|
||||
|
||||
# Basic ride info
|
||||
if ride.name:
|
||||
search_parts.append(ride.name)
|
||||
if ride.description:
|
||||
search_parts.append(ride.description)
|
||||
|
||||
|
||||
# Park info
|
||||
if ride.park:
|
||||
search_parts.append(ride.park.name)
|
||||
@@ -46,11 +46,11 @@ def populate_computed_fields(apps, schema_editor):
|
||||
search_parts.append(ride.park.location.state)
|
||||
if ride.park.location.country:
|
||||
search_parts.append(ride.park.location.country)
|
||||
|
||||
|
||||
# Park area
|
||||
if ride.park_area:
|
||||
search_parts.append(ride.park_area.name)
|
||||
|
||||
|
||||
# Category
|
||||
if ride.category:
|
||||
category_choices = [
|
||||
@@ -65,7 +65,7 @@ def populate_computed_fields(apps, schema_editor):
|
||||
category_display = dict(category_choices).get(ride.category, '')
|
||||
if category_display:
|
||||
search_parts.append(category_display)
|
||||
|
||||
|
||||
# Status
|
||||
if ride.status:
|
||||
status_choices = [
|
||||
@@ -82,21 +82,21 @@ def populate_computed_fields(apps, schema_editor):
|
||||
status_display = dict(status_choices).get(ride.status, '')
|
||||
if status_display:
|
||||
search_parts.append(status_display)
|
||||
|
||||
|
||||
# Companies
|
||||
if ride.manufacturer:
|
||||
search_parts.append(ride.manufacturer.name)
|
||||
if ride.designer:
|
||||
search_parts.append(ride.designer.name)
|
||||
|
||||
|
||||
# Ride model
|
||||
if ride.ride_model:
|
||||
search_parts.append(ride.ride_model.name)
|
||||
if ride.ride_model.manufacturer:
|
||||
search_parts.append(ride.ride_model.manufacturer.name)
|
||||
|
||||
|
||||
ride.search_text = ' '.join(filter(None, search_parts)).lower()
|
||||
|
||||
|
||||
# Bulk update all rides
|
||||
Ride.objects.bulk_update(rides, ['opening_year', 'search_text'], batch_size=1000)
|
||||
|
||||
@@ -104,7 +104,7 @@ def populate_computed_fields(apps, schema_editor):
|
||||
def reverse_populate_computed_fields(apps, schema_editor):
|
||||
"""Clear computed fields (reverse operation)."""
|
||||
Ride = apps.get_model('rides', 'Ride')
|
||||
|
||||
|
||||
# Disable pghistory triggers during bulk operations
|
||||
with pghistory.context(disable=True):
|
||||
Ride.objects.all().update(opening_year=None, search_text='')
|
||||
|
||||
@@ -28,151 +28,151 @@ class Migration(migrations.Migration):
|
||||
"CREATE INDEX rides_ride_park_category_idx ON rides_ride (park_id, category) WHERE category != '';",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_park_category_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Composite index for park + status filtering (common)
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_park_status_idx ON rides_ride (park_id, status);",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_park_status_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Composite index for category + status filtering
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_category_status_idx ON rides_ride (category, status) WHERE category != '';",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_category_status_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Composite index for manufacturer + category
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_manufacturer_category_idx ON rides_ride (manufacturer_id, category) WHERE manufacturer_id IS NOT NULL AND category != '';",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_manufacturer_category_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Composite index for opening year + category (for timeline filtering)
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_opening_year_category_idx ON rides_ride (opening_year, category) WHERE opening_year IS NOT NULL AND category != '';",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_opening_year_category_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Partial index for operating rides only (most common filter)
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_operating_only_idx ON rides_ride (park_id, category, opening_year) WHERE status = 'OPERATING';",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_operating_only_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Partial index for roller coasters only (popular category)
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_roller_coasters_idx ON rides_ride (park_id, status, opening_year) WHERE category = 'RC';",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_roller_coasters_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Covering index for list views (includes commonly displayed fields)
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_list_covering_idx ON rides_ride (park_id, category, status) INCLUDE (name, opening_date, average_rating);",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_list_covering_idx;"
|
||||
),
|
||||
|
||||
|
||||
# GIN index for full-text search on computed search_text field
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_search_text_gin_idx ON rides_ride USING gin(to_tsvector('english', search_text));",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_search_text_gin_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Trigram index for fuzzy text search
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_search_text_trgm_idx ON rides_ride USING gin(search_text gin_trgm_ops);",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_search_text_trgm_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Index for rating-based filtering
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_rating_idx ON rides_ride (average_rating) WHERE average_rating IS NOT NULL;",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_rating_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Index for capacity-based filtering
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_capacity_idx ON rides_ride (capacity_per_hour) WHERE capacity_per_hour IS NOT NULL;",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_capacity_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Index for height requirement filtering
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_height_req_idx ON rides_ride (min_height_in, max_height_in) WHERE min_height_in IS NOT NULL OR max_height_in IS NOT NULL;",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_height_req_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Composite index for ride model filtering
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_model_manufacturer_idx ON rides_ride (ride_model_id, manufacturer_id) WHERE ride_model_id IS NOT NULL;",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_model_manufacturer_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Index for designer filtering
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_designer_idx ON rides_ride (designer_id, category) WHERE designer_id IS NOT NULL;",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_designer_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Index for park area filtering
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ride_park_area_idx ON rides_ride (park_area_id, status) WHERE park_area_id IS NOT NULL;",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ride_park_area_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Roller coaster stats indexes for performance
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_rollercoasterstats_height_idx ON rides_rollercoasterstats (height_ft) WHERE height_ft IS NOT NULL;",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_rollercoasterstats_height_idx;"
|
||||
),
|
||||
|
||||
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_rollercoasterstats_speed_idx ON rides_rollercoasterstats (speed_mph) WHERE speed_mph IS NOT NULL;",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_rollercoasterstats_speed_idx;"
|
||||
),
|
||||
|
||||
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_rollercoasterstats_inversions_idx ON rides_rollercoasterstats (inversions);",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_rollercoasterstats_inversions_idx;"
|
||||
),
|
||||
|
||||
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_rollercoasterstats_type_material_idx ON rides_rollercoasterstats (roller_coaster_type, track_material);",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_rollercoasterstats_type_material_idx;"
|
||||
),
|
||||
|
||||
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_rollercoasterstats_launch_type_idx ON rides_rollercoasterstats (launch_type);",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_rollercoasterstats_launch_type_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Composite index for complex roller coaster filtering
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_rollercoasterstats_complex_idx ON rides_rollercoasterstats (roller_coaster_type, track_material, launch_type) INCLUDE (height_ft, speed_mph, inversions);",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_rollercoasterstats_complex_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Index for ride model filtering and search
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ridemodel_manufacturer_category_idx ON rides_ridemodel (manufacturer_id, category) WHERE manufacturer_id IS NOT NULL;",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ridemodel_manufacturer_category_idx;"
|
||||
),
|
||||
|
||||
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_ridemodel_name_trgm_idx ON rides_ridemodel USING gin(name gin_trgm_ops);",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_ridemodel_name_trgm_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Index for company role-based filtering
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_company_manufacturer_role_idx ON rides_company USING gin(roles) WHERE 'MANUFACTURER' = ANY(roles);",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_company_manufacturer_role_idx;"
|
||||
),
|
||||
|
||||
|
||||
migrations.RunSQL(
|
||||
"CREATE INDEX rides_company_designer_role_idx ON rides_company USING gin(roles) WHERE 'DESIGNER' = ANY(roles);",
|
||||
reverse_sql="DROP INDEX IF EXISTS rides_company_designer_role_idx;"
|
||||
),
|
||||
|
||||
|
||||
# Ensure trigram extension is available for fuzzy search
|
||||
migrations.RunSQL(
|
||||
"CREATE EXTENSION IF NOT EXISTS pg_trgm;",
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# Generated by Django 5.2.5 on 2025-09-15 17:35
|
||||
|
||||
import apps.core.choices.fields
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
import apps.core.choices.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# Generated by Django 5.2.5 on 2025-09-15 18:07
|
||||
|
||||
import apps.core.choices.fields
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations
|
||||
|
||||
import apps.core.choices.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# Generated by Django 5.2.5 on 2025-09-15 19:06
|
||||
|
||||
import apps.core.choices.fields
|
||||
from django.db import migrations
|
||||
|
||||
import apps.core.choices.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# Generated by Django 5.2.5 on 2025-09-17 01:25
|
||||
|
||||
import apps.core.choices.fields
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations
|
||||
|
||||
import apps.core.choices.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# Generated by Django 5.1.3 on 2025-12-21 03:20
|
||||
|
||||
import apps.core.state_machine.fields
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
import apps.core.state_machine.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# Generated by Django 5.1.6 on 2025-12-26 14:10
|
||||
|
||||
import apps.core.choices.fields
|
||||
import django.contrib.postgres.fields
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
import apps.core.choices.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
|
||||
@@ -0,0 +1,533 @@
|
||||
# Generated by Django 5.2.9 on 2025-12-27 20:58
|
||||
|
||||
import django.db.models.deletion
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("pghistory", "0007_auto_20250421_0444"),
|
||||
("rides", "0028_ridecredit_ridecreditevent_ridecredit_insert_insert_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="DarkRideStats",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("scene_count", models.PositiveIntegerField(default=0, help_text="Number of themed scenes")),
|
||||
(
|
||||
"animatronic_count",
|
||||
models.PositiveIntegerField(default=0, help_text="Number of animatronic figures"),
|
||||
),
|
||||
(
|
||||
"has_projection_technology",
|
||||
models.BooleanField(default=False, help_text="Whether the ride uses projection mapping or screens"),
|
||||
),
|
||||
(
|
||||
"is_interactive",
|
||||
models.BooleanField(
|
||||
default=False, help_text="Whether riders can interact with elements (shooting, etc.)"
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_system",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
help_text="Type of ride system (Omnimover, Trackless, Classic Track, etc.)",
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
(
|
||||
"uses_practical_effects",
|
||||
models.BooleanField(default=True, help_text="Whether the ride uses practical/physical effects"),
|
||||
),
|
||||
(
|
||||
"uses_motion_base",
|
||||
models.BooleanField(default=False, help_text="Whether vehicles have motion simulation capability"),
|
||||
),
|
||||
(
|
||||
"ride",
|
||||
models.OneToOneField(
|
||||
help_text="Ride these dark ride statistics belong to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="dark_stats",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Dark Ride Statistics",
|
||||
"verbose_name_plural": "Dark Ride Statistics",
|
||||
"ordering": ["ride"],
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="DarkRideStatsEvent",
|
||||
fields=[
|
||||
("pgh_id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("pgh_created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("pgh_label", models.TextField(help_text="The event label.")),
|
||||
("id", models.BigIntegerField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("scene_count", models.PositiveIntegerField(default=0, help_text="Number of themed scenes")),
|
||||
(
|
||||
"animatronic_count",
|
||||
models.PositiveIntegerField(default=0, help_text="Number of animatronic figures"),
|
||||
),
|
||||
(
|
||||
"has_projection_technology",
|
||||
models.BooleanField(default=False, help_text="Whether the ride uses projection mapping or screens"),
|
||||
),
|
||||
(
|
||||
"is_interactive",
|
||||
models.BooleanField(
|
||||
default=False, help_text="Whether riders can interact with elements (shooting, etc.)"
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_system",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
help_text="Type of ride system (Omnimover, Trackless, Classic Track, etc.)",
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
(
|
||||
"uses_practical_effects",
|
||||
models.BooleanField(default=True, help_text="Whether the ride uses practical/physical effects"),
|
||||
),
|
||||
(
|
||||
"uses_motion_base",
|
||||
models.BooleanField(default=False, help_text="Whether vehicles have motion simulation capability"),
|
||||
),
|
||||
(
|
||||
"pgh_context",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
to="pghistory.context",
|
||||
),
|
||||
),
|
||||
(
|
||||
"pgh_obj",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="events",
|
||||
to="rides.darkridestats",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
help_text="Ride these dark ride statistics belong to",
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="FlatRideStats",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"max_height_ft",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=2, help_text="Maximum ride height in feet", max_digits=6, null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"rotation_speed_rpm",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=2, help_text="Maximum rotation speed in RPM", max_digits=5, null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"swing_angle_degrees",
|
||||
models.PositiveIntegerField(
|
||||
blank=True, help_text="Maximum swing angle in degrees (for swinging rides)", null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"motion_type",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("SPINNING", "Spinning"),
|
||||
("SWINGING", "Swinging"),
|
||||
("BOUNCING", "Bouncing"),
|
||||
("ROTATING", "Rotating"),
|
||||
("DROPPING", "Dropping"),
|
||||
("MIXED", "Mixed Motion"),
|
||||
],
|
||||
default="SPINNING",
|
||||
help_text="Primary type of motion",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
("arm_count", models.PositiveIntegerField(blank=True, help_text="Number of arms/gondolas", null=True)),
|
||||
(
|
||||
"seats_per_gondola",
|
||||
models.PositiveIntegerField(blank=True, help_text="Number of seats per gondola/arm", null=True),
|
||||
),
|
||||
(
|
||||
"max_g_force",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=2, help_text="Maximum G-force experienced", max_digits=4, null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride",
|
||||
models.OneToOneField(
|
||||
help_text="Ride these flat ride statistics belong to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="flat_stats",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Flat Ride Statistics",
|
||||
"verbose_name_plural": "Flat Ride Statistics",
|
||||
"ordering": ["ride"],
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="FlatRideStatsEvent",
|
||||
fields=[
|
||||
("pgh_id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("pgh_created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("pgh_label", models.TextField(help_text="The event label.")),
|
||||
("id", models.BigIntegerField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"max_height_ft",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=2, help_text="Maximum ride height in feet", max_digits=6, null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"rotation_speed_rpm",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=2, help_text="Maximum rotation speed in RPM", max_digits=5, null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"swing_angle_degrees",
|
||||
models.PositiveIntegerField(
|
||||
blank=True, help_text="Maximum swing angle in degrees (for swinging rides)", null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"motion_type",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("SPINNING", "Spinning"),
|
||||
("SWINGING", "Swinging"),
|
||||
("BOUNCING", "Bouncing"),
|
||||
("ROTATING", "Rotating"),
|
||||
("DROPPING", "Dropping"),
|
||||
("MIXED", "Mixed Motion"),
|
||||
],
|
||||
default="SPINNING",
|
||||
help_text="Primary type of motion",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
("arm_count", models.PositiveIntegerField(blank=True, help_text="Number of arms/gondolas", null=True)),
|
||||
(
|
||||
"seats_per_gondola",
|
||||
models.PositiveIntegerField(blank=True, help_text="Number of seats per gondola/arm", null=True),
|
||||
),
|
||||
(
|
||||
"max_g_force",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=2, help_text="Maximum G-force experienced", max_digits=4, null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"pgh_context",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
to="pghistory.context",
|
||||
),
|
||||
),
|
||||
(
|
||||
"pgh_obj",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="events",
|
||||
to="rides.flatridestats",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
help_text="Ride these flat ride statistics belong to",
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="WaterRideStats",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"wetness_level",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("DRY", "Dry - No water contact"),
|
||||
("MILD", "Mild - Light misting"),
|
||||
("MODERATE", "Moderate - Some splashing"),
|
||||
("SOAKING", "Soaking - Prepare to get drenched"),
|
||||
],
|
||||
default="MODERATE",
|
||||
help_text="How wet riders typically get",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
(
|
||||
"splash_height_ft",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=2, help_text="Maximum splash height in feet", max_digits=5, null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"has_splash_zone",
|
||||
models.BooleanField(
|
||||
default=False, help_text="Whether there is a designated splash zone for spectators"
|
||||
),
|
||||
),
|
||||
(
|
||||
"boat_capacity",
|
||||
models.PositiveIntegerField(blank=True, help_text="Number of riders per boat/raft", null=True),
|
||||
),
|
||||
(
|
||||
"uses_flume",
|
||||
models.BooleanField(default=False, help_text="Whether the ride uses a flume/log system"),
|
||||
),
|
||||
(
|
||||
"rapids_sections",
|
||||
models.PositiveIntegerField(default=0, help_text="Number of rapids/whitewater sections"),
|
||||
),
|
||||
(
|
||||
"ride",
|
||||
models.OneToOneField(
|
||||
help_text="Ride these water statistics belong to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="water_stats",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Water Ride Statistics",
|
||||
"verbose_name_plural": "Water Ride Statistics",
|
||||
"ordering": ["ride"],
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="WaterRideStatsEvent",
|
||||
fields=[
|
||||
("pgh_id", models.AutoField(primary_key=True, serialize=False)),
|
||||
("pgh_created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("pgh_label", models.TextField(help_text="The event label.")),
|
||||
("id", models.BigIntegerField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"wetness_level",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("DRY", "Dry - No water contact"),
|
||||
("MILD", "Mild - Light misting"),
|
||||
("MODERATE", "Moderate - Some splashing"),
|
||||
("SOAKING", "Soaking - Prepare to get drenched"),
|
||||
],
|
||||
default="MODERATE",
|
||||
help_text="How wet riders typically get",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
(
|
||||
"splash_height_ft",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=2, help_text="Maximum splash height in feet", max_digits=5, null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"has_splash_zone",
|
||||
models.BooleanField(
|
||||
default=False, help_text="Whether there is a designated splash zone for spectators"
|
||||
),
|
||||
),
|
||||
(
|
||||
"boat_capacity",
|
||||
models.PositiveIntegerField(blank=True, help_text="Number of riders per boat/raft", null=True),
|
||||
),
|
||||
(
|
||||
"uses_flume",
|
||||
models.BooleanField(default=False, help_text="Whether the ride uses a flume/log system"),
|
||||
),
|
||||
(
|
||||
"rapids_sections",
|
||||
models.PositiveIntegerField(default=0, help_text="Number of rapids/whitewater sections"),
|
||||
),
|
||||
(
|
||||
"pgh_context",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
to="pghistory.context",
|
||||
),
|
||||
),
|
||||
(
|
||||
"pgh_obj",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="events",
|
||||
to="rides.waterridestats",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
help_text="Ride these water statistics belong to",
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="darkridestats",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_darkridestatsevent" ("animatronic_count", "created_at", "has_projection_technology", "id", "is_interactive", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "ride_id", "ride_system", "scene_count", "updated_at", "uses_motion_base", "uses_practical_effects") VALUES (NEW."animatronic_count", NEW."created_at", NEW."has_projection_technology", NEW."id", NEW."is_interactive", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."ride_id", NEW."ride_system", NEW."scene_count", NEW."updated_at", NEW."uses_motion_base", NEW."uses_practical_effects"); RETURN NULL;',
|
||||
hash="055ece465263a190b67dda7258c4bf26fa939107",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_78d6d",
|
||||
table="rides_darkridestats",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="darkridestats",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "rides_darkridestatsevent" ("animatronic_count", "created_at", "has_projection_technology", "id", "is_interactive", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "ride_id", "ride_system", "scene_count", "updated_at", "uses_motion_base", "uses_practical_effects") VALUES (NEW."animatronic_count", NEW."created_at", NEW."has_projection_technology", NEW."id", NEW."is_interactive", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."ride_id", NEW."ride_system", NEW."scene_count", NEW."updated_at", NEW."uses_motion_base", NEW."uses_practical_effects"); RETURN NULL;',
|
||||
hash="e7421fdd5dd3f044c5cc324db3e5d948e8f39afe",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_8eac1",
|
||||
table="rides_darkridestats",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="flatridestats",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_flatridestatsevent" ("arm_count", "created_at", "id", "max_g_force", "max_height_ft", "motion_type", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "ride_id", "rotation_speed_rpm", "seats_per_gondola", "swing_angle_degrees", "updated_at") VALUES (NEW."arm_count", NEW."created_at", NEW."id", NEW."max_g_force", NEW."max_height_ft", NEW."motion_type", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."ride_id", NEW."rotation_speed_rpm", NEW."seats_per_gondola", NEW."swing_angle_degrees", NEW."updated_at"); RETURN NULL;',
|
||||
hash="04edef9ce6235f57c5b53f052a7fe392835f2971",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_a589a",
|
||||
table="rides_flatridestats",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="flatridestats",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "rides_flatridestatsevent" ("arm_count", "created_at", "id", "max_g_force", "max_height_ft", "motion_type", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "ride_id", "rotation_speed_rpm", "seats_per_gondola", "swing_angle_degrees", "updated_at") VALUES (NEW."arm_count", NEW."created_at", NEW."id", NEW."max_g_force", NEW."max_height_ft", NEW."motion_type", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."ride_id", NEW."rotation_speed_rpm", NEW."seats_per_gondola", NEW."swing_angle_degrees", NEW."updated_at"); RETURN NULL;',
|
||||
hash="6f48930fae214744ad60cf8755ee0d50897d1040",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_f949f",
|
||||
table="rides_flatridestats",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="waterridestats",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_waterridestatsevent" ("boat_capacity", "created_at", "has_splash_zone", "id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rapids_sections", "ride_id", "splash_height_ft", "updated_at", "uses_flume", "wetness_level") VALUES (NEW."boat_capacity", NEW."created_at", NEW."has_splash_zone", NEW."id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."rapids_sections", NEW."ride_id", NEW."splash_height_ft", NEW."updated_at", NEW."uses_flume", NEW."wetness_level"); RETURN NULL;',
|
||||
hash="bb61031dc606f90bf9970f76417b30a72d8469ce",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_fb731",
|
||||
table="rides_waterridestats",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="waterridestats",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "rides_waterridestatsevent" ("boat_capacity", "created_at", "has_splash_zone", "id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rapids_sections", "ride_id", "splash_height_ft", "updated_at", "uses_flume", "wetness_level") VALUES (NEW."boat_capacity", NEW."created_at", NEW."has_splash_zone", NEW."id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."rapids_sections", NEW."ride_id", NEW."splash_height_ft", NEW."updated_at", NEW."uses_flume", NEW."wetness_level"); RETURN NULL;',
|
||||
hash="98404ec47c9b8d577f0a408a1182f9adffda7784",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_4f7a3",
|
||||
table="rides_waterridestats",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user