mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2026-02-05 09:45:17 -05:00
lol
This commit is contained in:
@@ -0,0 +1,454 @@
|
||||
# Generated by Django 5.2.9 on 2026-01-01 21:25
|
||||
|
||||
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", "0029_darkridestats_darkridestatsevent_flatridestats_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="KiddieRideStats",
|
||||
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)),
|
||||
(
|
||||
"min_age",
|
||||
models.PositiveIntegerField(blank=True, help_text="Minimum recommended age in years", null=True),
|
||||
),
|
||||
(
|
||||
"max_age",
|
||||
models.PositiveIntegerField(blank=True, help_text="Maximum recommended age in years", null=True),
|
||||
),
|
||||
(
|
||||
"educational_theme",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
help_text="Educational theme if applicable (e.g., 'Dinosaurs', 'Space')",
|
||||
max_length=200,
|
||||
),
|
||||
),
|
||||
(
|
||||
"character_theme",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
help_text="Character theme if applicable (e.g., 'Paw Patrol', 'Peppa Pig')",
|
||||
max_length=200,
|
||||
),
|
||||
),
|
||||
(
|
||||
"guardian_required",
|
||||
models.BooleanField(default=False, help_text="Whether a guardian must be present during the ride"),
|
||||
),
|
||||
(
|
||||
"adult_ride_along",
|
||||
models.BooleanField(default=True, help_text="Whether adults can ride along with children"),
|
||||
),
|
||||
(
|
||||
"seats_per_vehicle",
|
||||
models.PositiveIntegerField(blank=True, help_text="Number of seats per ride vehicle", null=True),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Kiddie Ride Statistics",
|
||||
"verbose_name_plural": "Kiddie Ride Statistics",
|
||||
"ordering": ["ride"],
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="KiddieRideStatsEvent",
|
||||
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)),
|
||||
(
|
||||
"min_age",
|
||||
models.PositiveIntegerField(blank=True, help_text="Minimum recommended age in years", null=True),
|
||||
),
|
||||
(
|
||||
"max_age",
|
||||
models.PositiveIntegerField(blank=True, help_text="Maximum recommended age in years", null=True),
|
||||
),
|
||||
(
|
||||
"educational_theme",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
help_text="Educational theme if applicable (e.g., 'Dinosaurs', 'Space')",
|
||||
max_length=200,
|
||||
),
|
||||
),
|
||||
(
|
||||
"character_theme",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
help_text="Character theme if applicable (e.g., 'Paw Patrol', 'Peppa Pig')",
|
||||
max_length=200,
|
||||
),
|
||||
),
|
||||
(
|
||||
"guardian_required",
|
||||
models.BooleanField(default=False, help_text="Whether a guardian must be present during the ride"),
|
||||
),
|
||||
(
|
||||
"adult_ride_along",
|
||||
models.BooleanField(default=True, help_text="Whether adults can ride along with children"),
|
||||
),
|
||||
(
|
||||
"seats_per_vehicle",
|
||||
models.PositiveIntegerField(blank=True, help_text="Number of seats per ride vehicle", null=True),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TransportationStats",
|
||||
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)),
|
||||
(
|
||||
"transport_type",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("TRAIN", "Train"),
|
||||
("MONORAIL", "Monorail"),
|
||||
("SKYLIFT", "Skylift / Chairlift"),
|
||||
("FERRY", "Ferry / Boat"),
|
||||
("PEOPLEMOVER", "PeopleMover"),
|
||||
("CABLE_CAR", "Cable Car"),
|
||||
("TRAM", "Tram"),
|
||||
],
|
||||
default="TRAIN",
|
||||
help_text="Type of transportation",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
(
|
||||
"route_length_ft",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=2, help_text="Total route length in feet", max_digits=8, null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"stations_count",
|
||||
models.PositiveIntegerField(
|
||||
blank=True, help_text="Number of stations/stops on the route", null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"vehicle_capacity",
|
||||
models.PositiveIntegerField(blank=True, help_text="Passenger capacity per vehicle", null=True),
|
||||
),
|
||||
(
|
||||
"vehicles_count",
|
||||
models.PositiveIntegerField(
|
||||
blank=True, help_text="Total number of vehicles in operation", null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"round_trip_duration_minutes",
|
||||
models.PositiveIntegerField(
|
||||
blank=True, help_text="Duration of a complete round trip in minutes", null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"scenic_highlights",
|
||||
models.TextField(blank=True, help_text="Notable scenic views or attractions along the route"),
|
||||
),
|
||||
(
|
||||
"is_one_way",
|
||||
models.BooleanField(
|
||||
default=False, help_text="Whether this is a one-way transportation (vs round-trip)"
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Transportation Statistics",
|
||||
"verbose_name_plural": "Transportation Statistics",
|
||||
"ordering": ["ride"],
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TransportationStatsEvent",
|
||||
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)),
|
||||
(
|
||||
"transport_type",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("TRAIN", "Train"),
|
||||
("MONORAIL", "Monorail"),
|
||||
("SKYLIFT", "Skylift / Chairlift"),
|
||||
("FERRY", "Ferry / Boat"),
|
||||
("PEOPLEMOVER", "PeopleMover"),
|
||||
("CABLE_CAR", "Cable Car"),
|
||||
("TRAM", "Tram"),
|
||||
],
|
||||
default="TRAIN",
|
||||
help_text="Type of transportation",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
(
|
||||
"route_length_ft",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=2, help_text="Total route length in feet", max_digits=8, null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"stations_count",
|
||||
models.PositiveIntegerField(
|
||||
blank=True, help_text="Number of stations/stops on the route", null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"vehicle_capacity",
|
||||
models.PositiveIntegerField(blank=True, help_text="Passenger capacity per vehicle", null=True),
|
||||
),
|
||||
(
|
||||
"vehicles_count",
|
||||
models.PositiveIntegerField(
|
||||
blank=True, help_text="Total number of vehicles in operation", null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"round_trip_duration_minutes",
|
||||
models.PositiveIntegerField(
|
||||
blank=True, help_text="Duration of a complete round trip in minutes", null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"scenic_highlights",
|
||||
models.TextField(blank=True, help_text="Notable scenic views or attractions along the route"),
|
||||
),
|
||||
(
|
||||
"is_one_way",
|
||||
models.BooleanField(
|
||||
default=False, help_text="Whether this is a one-way transportation (vs round-trip)"
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name="ridecredit",
|
||||
options={
|
||||
"ordering": ["display_order", "-last_ridden_at", "-first_ridden_at", "-created_at"],
|
||||
"verbose_name": "Ride Credit",
|
||||
"verbose_name_plural": "Ride Credits",
|
||||
},
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="ridecredit",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="ridecredit",
|
||||
name="update_update",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="ridecredit",
|
||||
name="display_order",
|
||||
field=models.PositiveIntegerField(default=0, help_text="User-defined display order for drag-drop sorting"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="ridecreditevent",
|
||||
name="display_order",
|
||||
field=models.PositiveIntegerField(default=0, help_text="User-defined display order for drag-drop sorting"),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="ridecredit",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_ridecreditevent" ("count", "created_at", "display_order", "first_ridden_at", "id", "last_ridden_at", "notes", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rating", "ride_id", "updated_at", "user_id") VALUES (NEW."count", NEW."created_at", NEW."display_order", NEW."first_ridden_at", NEW."id", NEW."last_ridden_at", NEW."notes", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."rating", NEW."ride_id", NEW."updated_at", NEW."user_id"); RETURN NULL;',
|
||||
hash="680f93dab99a404aea8f73f8328eff04cd561254",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_00439",
|
||||
table="rides_ridecredit",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="ridecredit",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "rides_ridecreditevent" ("count", "created_at", "display_order", "first_ridden_at", "id", "last_ridden_at", "notes", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rating", "ride_id", "updated_at", "user_id") VALUES (NEW."count", NEW."created_at", NEW."display_order", NEW."first_ridden_at", NEW."id", NEW."last_ridden_at", NEW."notes", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."rating", NEW."ride_id", NEW."updated_at", NEW."user_id"); RETURN NULL;',
|
||||
hash="e9889a572acd9261c1355ab47458f3eaf2b07c13",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_32a65",
|
||||
table="rides_ridecredit",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="kiddieridestats",
|
||||
name="ride",
|
||||
field=models.OneToOneField(
|
||||
help_text="Ride these kiddie ride statistics belong to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="kiddie_stats",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="kiddieridestatsevent",
|
||||
name="pgh_context",
|
||||
field=models.ForeignKey(
|
||||
db_constraint=False,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
to="pghistory.context",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="kiddieridestatsevent",
|
||||
name="pgh_obj",
|
||||
field=models.ForeignKey(
|
||||
db_constraint=False,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="events",
|
||||
to="rides.kiddieridestats",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="kiddieridestatsevent",
|
||||
name="ride",
|
||||
field=models.ForeignKey(
|
||||
db_constraint=False,
|
||||
help_text="Ride these kiddie ride statistics belong to",
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="transportationstats",
|
||||
name="ride",
|
||||
field=models.OneToOneField(
|
||||
help_text="Ride these transportation statistics belong to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="transport_stats",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="transportationstatsevent",
|
||||
name="pgh_context",
|
||||
field=models.ForeignKey(
|
||||
db_constraint=False,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
to="pghistory.context",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="transportationstatsevent",
|
||||
name="pgh_obj",
|
||||
field=models.ForeignKey(
|
||||
db_constraint=False,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="events",
|
||||
to="rides.transportationstats",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="transportationstatsevent",
|
||||
name="ride",
|
||||
field=models.ForeignKey(
|
||||
db_constraint=False,
|
||||
help_text="Ride these transportation statistics belong to",
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="kiddieridestats",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_kiddieridestatsevent" ("adult_ride_along", "character_theme", "created_at", "educational_theme", "guardian_required", "id", "max_age", "min_age", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "ride_id", "seats_per_vehicle", "updated_at") VALUES (NEW."adult_ride_along", NEW."character_theme", NEW."created_at", NEW."educational_theme", NEW."guardian_required", NEW."id", NEW."max_age", NEW."min_age", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."ride_id", NEW."seats_per_vehicle", NEW."updated_at"); RETURN NULL;',
|
||||
hash="b5d181566e5d0710c5b4093a5b61dc54591e5639",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_9949f",
|
||||
table="rides_kiddieridestats",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="kiddieridestats",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "rides_kiddieridestatsevent" ("adult_ride_along", "character_theme", "created_at", "educational_theme", "guardian_required", "id", "max_age", "min_age", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "ride_id", "seats_per_vehicle", "updated_at") VALUES (NEW."adult_ride_along", NEW."character_theme", NEW."created_at", NEW."educational_theme", NEW."guardian_required", NEW."id", NEW."max_age", NEW."min_age", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."ride_id", NEW."seats_per_vehicle", NEW."updated_at"); RETURN NULL;',
|
||||
hash="672bb3e42cda03094d9300b6e0d9d89b2797bd05",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_fb19d",
|
||||
table="rides_kiddieridestats",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="transportationstats",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_transportationstatsevent" ("created_at", "id", "is_one_way", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "ride_id", "round_trip_duration_minutes", "route_length_ft", "scenic_highlights", "stations_count", "transport_type", "updated_at", "vehicle_capacity", "vehicles_count") VALUES (NEW."created_at", NEW."id", NEW."is_one_way", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."ride_id", NEW."round_trip_duration_minutes", NEW."route_length_ft", NEW."scenic_highlights", NEW."stations_count", NEW."transport_type", NEW."updated_at", NEW."vehicle_capacity", NEW."vehicles_count"); RETURN NULL;',
|
||||
hash="95a70a6e71eb5ea32726a19e5eb6286c20b19952",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_c811e",
|
||||
table="rides_transportationstats",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="transportationstats",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "rides_transportationstatsevent" ("created_at", "id", "is_one_way", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "ride_id", "round_trip_duration_minutes", "route_length_ft", "scenic_highlights", "stations_count", "transport_type", "updated_at", "vehicle_capacity", "vehicles_count") VALUES (NEW."created_at", NEW."id", NEW."is_one_way", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."ride_id", NEW."round_trip_duration_minutes", NEW."route_length_ft", NEW."scenic_highlights", NEW."stations_count", NEW."transport_type", NEW."updated_at", NEW."vehicle_capacity", NEW."vehicles_count"); RETURN NULL;',
|
||||
hash="901b16a5411e78635442895d7107b298634d25c3",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_ccccf",
|
||||
table="rides_transportationstats",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
155
backend/apps/rides/migrations/0031_add_ride_name_history.py
Normal file
155
backend/apps/rides/migrations/0031_add_ride_name_history.py
Normal file
@@ -0,0 +1,155 @@
|
||||
# Generated by Django 5.2.9 on 2026-01-02 00:33
|
||||
|
||||
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", "0030_add_kiddie_and_transportation_stats"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="RideNameHistory",
|
||||
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)),
|
||||
("former_name", models.CharField(help_text="The previous name of the ride", max_length=200)),
|
||||
(
|
||||
"from_year",
|
||||
models.PositiveSmallIntegerField(
|
||||
blank=True, help_text="Year the ride started using this name", null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"to_year",
|
||||
models.PositiveSmallIntegerField(
|
||||
blank=True, help_text="Year the ride stopped using this name", null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"reason",
|
||||
models.CharField(
|
||||
blank=True, help_text="Reason for the name change (e.g., 'Retheme to Peanuts')", max_length=500
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride",
|
||||
models.ForeignKey(
|
||||
help_text="The ride this name history entry belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="former_names",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Ride Name History",
|
||||
"verbose_name_plural": "Ride Name Histories",
|
||||
"ordering": ["-to_year", "-from_year"],
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="RideNameHistoryEvent",
|
||||
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)),
|
||||
("former_name", models.CharField(help_text="The previous name of the ride", max_length=200)),
|
||||
(
|
||||
"from_year",
|
||||
models.PositiveSmallIntegerField(
|
||||
blank=True, help_text="Year the ride started using this name", null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"to_year",
|
||||
models.PositiveSmallIntegerField(
|
||||
blank=True, help_text="Year the ride stopped using this name", null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"reason",
|
||||
models.CharField(
|
||||
blank=True, help_text="Reason for the name change (e.g., 'Retheme to Peanuts')", max_length=500
|
||||
),
|
||||
),
|
||||
(
|
||||
"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.ridenamehistory",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
help_text="The ride this name history entry belongs to",
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="ridenamehistory",
|
||||
index=models.Index(fields=["ride", "-to_year"], name="rides_riden_ride_id_b546e5_idx"),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="ridenamehistory",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_ridenamehistoryevent" ("created_at", "former_name", "from_year", "id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "reason", "ride_id", "to_year", "updated_at") VALUES (NEW."created_at", NEW."former_name", NEW."from_year", NEW."id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."reason", NEW."ride_id", NEW."to_year", NEW."updated_at"); RETURN NULL;',
|
||||
hash="b79231914244e431999014db94fd52759cc41541",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_ca1f7",
|
||||
table="rides_ridenamehistory",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="ridenamehistory",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "rides_ridenamehistoryevent" ("created_at", "former_name", "from_year", "id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "reason", "ride_id", "to_year", "updated_at") VALUES (NEW."created_at", NEW."former_name", NEW."from_year", NEW."id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."reason", NEW."ride_id", NEW."to_year", NEW."updated_at"); RETURN NULL;',
|
||||
hash="c760d29ecb57f1f3c92e76c7f5d45027db136b84",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_99e4e",
|
||||
table="rides_ridenamehistory",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,96 @@
|
||||
# Generated by Django 5.2.9 on 2026-01-02 02:30
|
||||
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("rides", "0031_add_ride_name_history"),
|
||||
]
|
||||
|
||||
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="closing_date_precision",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[("YEAR", "Year"), ("MONTH", "Month"), ("DAY", "Day")],
|
||||
default="DAY",
|
||||
help_text="Precision of the closing date",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="ride",
|
||||
name="opening_date_precision",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[("YEAR", "Year"), ("MONTH", "Month"), ("DAY", "Day")],
|
||||
default="DAY",
|
||||
help_text="Precision of the opening date",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="rideevent",
|
||||
name="closing_date_precision",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[("YEAR", "Year"), ("MONTH", "Month"), ("DAY", "Day")],
|
||||
default="DAY",
|
||||
help_text="Precision of the closing date",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="rideevent",
|
||||
name="opening_date_precision",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[("YEAR", "Year"), ("MONTH", "Month"), ("DAY", "Day")],
|
||||
default="DAY",
|
||||
help_text="Precision of the opening date",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="ride",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_rideevent" ("average_rating", "banner_image_id", "capacity_per_hour", "card_image_id", "category", "closing_date", "closing_date_precision", "created_at", "description", "designer_id", "id", "manufacturer_id", "max_height_in", "min_height_in", "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", "post_closing_status", "ride_duration_seconds", "ride_model_id", "search_text", "slug", "status", "status_since", "updated_at", "url") VALUES (NEW."average_rating", NEW."banner_image_id", NEW."capacity_per_hour", NEW."card_image_id", NEW."category", NEW."closing_date", NEW."closing_date_precision", NEW."created_at", NEW."description", NEW."designer_id", NEW."id", NEW."manufacturer_id", NEW."max_height_in", NEW."min_height_in", 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."post_closing_status", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."search_text", NEW."slug", NEW."status", NEW."status_since", NEW."updated_at", NEW."url"); RETURN NULL;',
|
||||
hash="e0a64190a51762d71e695238a7ee9feedb95fd41",
|
||||
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" ("average_rating", "banner_image_id", "capacity_per_hour", "card_image_id", "category", "closing_date", "closing_date_precision", "created_at", "description", "designer_id", "id", "manufacturer_id", "max_height_in", "min_height_in", "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", "post_closing_status", "ride_duration_seconds", "ride_model_id", "search_text", "slug", "status", "status_since", "updated_at", "url") VALUES (NEW."average_rating", NEW."banner_image_id", NEW."capacity_per_hour", NEW."card_image_id", NEW."category", NEW."closing_date", NEW."closing_date_precision", NEW."created_at", NEW."description", NEW."designer_id", NEW."id", NEW."manufacturer_id", NEW."max_height_in", NEW."min_height_in", 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."post_closing_status", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."search_text", NEW."slug", NEW."status", NEW."status_since", NEW."updated_at", NEW."url"); RETURN NULL;',
|
||||
hash="e3991e794f1239191cfe9095bab207527123b94f",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_4917a",
|
||||
table="rides_ride",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,84 @@
|
||||
# Generated by Django 5.2.9 on 2026-01-02 02:36
|
||||
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("rides", "0032_add_date_precision_fields"),
|
||||
]
|
||||
|
||||
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="age_requirement",
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True, help_text="Minimum age requirement in years (if any)", null=True
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="ride",
|
||||
name="ride_sub_type",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
help_text="Sub-category of ride (e.g., 'Flying Coaster', 'Inverted Coaster', 'Log Flume')",
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="rideevent",
|
||||
name="age_requirement",
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True, help_text="Minimum age requirement in years (if any)", null=True
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="rideevent",
|
||||
name="ride_sub_type",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
help_text="Sub-category of ride (e.g., 'Flying Coaster', 'Inverted Coaster', 'Log Flume')",
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="ride",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_rideevent" ("age_requirement", "average_rating", "banner_image_id", "capacity_per_hour", "card_image_id", "category", "closing_date", "closing_date_precision", "created_at", "description", "designer_id", "id", "manufacturer_id", "max_height_in", "min_height_in", "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", "post_closing_status", "ride_duration_seconds", "ride_model_id", "ride_sub_type", "search_text", "slug", "status", "status_since", "updated_at", "url") VALUES (NEW."age_requirement", NEW."average_rating", NEW."banner_image_id", NEW."capacity_per_hour", NEW."card_image_id", NEW."category", NEW."closing_date", NEW."closing_date_precision", NEW."created_at", NEW."description", NEW."designer_id", NEW."id", NEW."manufacturer_id", NEW."max_height_in", NEW."min_height_in", 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."post_closing_status", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."ride_sub_type", NEW."search_text", NEW."slug", NEW."status", NEW."status_since", NEW."updated_at", NEW."url"); RETURN NULL;',
|
||||
hash="cd829a8030511234c62ed355a58c753d15d09df9",
|
||||
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", "average_rating", "banner_image_id", "capacity_per_hour", "card_image_id", "category", "closing_date", "closing_date_precision", "created_at", "description", "designer_id", "id", "manufacturer_id", "max_height_in", "min_height_in", "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", "post_closing_status", "ride_duration_seconds", "ride_model_id", "ride_sub_type", "search_text", "slug", "status", "status_since", "updated_at", "url") VALUES (NEW."age_requirement", NEW."average_rating", NEW."banner_image_id", NEW."capacity_per_hour", NEW."card_image_id", NEW."category", NEW."closing_date", NEW."closing_date_precision", NEW."created_at", NEW."description", NEW."designer_id", NEW."id", NEW."manufacturer_id", NEW."max_height_in", NEW."min_height_in", 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."post_closing_status", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."ride_sub_type", NEW."search_text", NEW."slug", NEW."status", NEW."status_since", NEW."updated_at", NEW."url"); RETURN NULL;',
|
||||
hash="32d2f4a4547c7fd91e136ea0ac378f1b6bb8ef30",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_4917a",
|
||||
table="rides_ride",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -12,19 +12,23 @@ from .company import Company
|
||||
from .credits import RideCredit
|
||||
from .location import RideLocation
|
||||
from .media import RidePhoto
|
||||
from .name_history import RideNameHistory
|
||||
from .rankings import RankingSnapshot, RidePairComparison, RideRanking
|
||||
from .reviews import RideReview
|
||||
from .rides import Ride, RideModel, RollerCoasterStats
|
||||
from .stats import DarkRideStats, FlatRideStats, WaterRideStats
|
||||
from .stats import DarkRideStats, FlatRideStats, KiddieRideStats, TransportationStats, WaterRideStats
|
||||
|
||||
__all__ = [
|
||||
# Primary models
|
||||
"Ride",
|
||||
"RideModel",
|
||||
"RideNameHistory",
|
||||
"RollerCoasterStats",
|
||||
"WaterRideStats",
|
||||
"DarkRideStats",
|
||||
"FlatRideStats",
|
||||
"KiddieRideStats",
|
||||
"TransportationStats",
|
||||
"Company",
|
||||
"RideLocation",
|
||||
"RideReview",
|
||||
@@ -35,3 +39,4 @@ __all__ = [
|
||||
"RidePairComparison",
|
||||
"RankingSnapshot",
|
||||
]
|
||||
|
||||
|
||||
73
backend/apps/rides/models/name_history.py
Normal file
73
backend/apps/rides/models/name_history.py
Normal file
@@ -0,0 +1,73 @@
|
||||
"""
|
||||
Ride Name History model for tracking historical ride names.
|
||||
|
||||
This model stores the history of name changes for rides, enabling display of
|
||||
former names on ride detail pages.
|
||||
"""
|
||||
|
||||
import pghistory
|
||||
from django.db import models
|
||||
|
||||
from apps.core.models import TrackedModel
|
||||
|
||||
|
||||
@pghistory.track()
|
||||
class RideNameHistory(TrackedModel):
|
||||
"""
|
||||
Tracks historical names of rides.
|
||||
|
||||
When a ride is renamed, this model stores the previous name along with
|
||||
the year range it was used and an optional reason for the change.
|
||||
"""
|
||||
|
||||
ride = models.ForeignKey(
|
||||
"rides.Ride",
|
||||
on_delete=models.CASCADE,
|
||||
related_name="former_names",
|
||||
help_text="The ride this name history entry belongs to",
|
||||
)
|
||||
former_name = models.CharField(
|
||||
max_length=200,
|
||||
help_text="The previous name of the ride",
|
||||
)
|
||||
from_year = models.PositiveSmallIntegerField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Year the ride started using this name",
|
||||
)
|
||||
to_year = models.PositiveSmallIntegerField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Year the ride stopped using this name",
|
||||
)
|
||||
reason = models.CharField(
|
||||
max_length=500,
|
||||
blank=True,
|
||||
help_text="Reason for the name change (e.g., 'Retheme to Peanuts')",
|
||||
)
|
||||
|
||||
class Meta(TrackedModel.Meta):
|
||||
verbose_name = "Ride Name History"
|
||||
verbose_name_plural = "Ride Name Histories"
|
||||
ordering = ["-to_year", "-from_year"]
|
||||
indexes = [
|
||||
models.Index(fields=["ride", "-to_year"]),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
year_range = ""
|
||||
if self.from_year and self.to_year:
|
||||
year_range = f" ({self.from_year}-{self.to_year})"
|
||||
elif self.to_year:
|
||||
year_range = f" (until {self.to_year})"
|
||||
elif self.from_year:
|
||||
year_range = f" (from {self.from_year})"
|
||||
return f"{self.former_name}{year_range}"
|
||||
|
||||
def clean(self):
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
if self.from_year and self.to_year and self.from_year > self.to_year:
|
||||
raise ValidationError(
|
||||
{"from_year": "From year cannot be after to year."}
|
||||
)
|
||||
@@ -508,7 +508,21 @@ class Ride(StateMachineMixin, TrackedModel):
|
||||
help_text="Status to change to after closing date",
|
||||
)
|
||||
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",
|
||||
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",
|
||||
blank=True,
|
||||
help_text="Precision of the closing date",
|
||||
)
|
||||
status_since = models.DateField(null=True, blank=True)
|
||||
min_height_in = models.PositiveIntegerField(null=True, blank=True)
|
||||
max_height_in = models.PositiveIntegerField(null=True, blank=True)
|
||||
@@ -516,6 +530,18 @@ class Ride(StateMachineMixin, TrackedModel):
|
||||
ride_duration_seconds = models.PositiveIntegerField(null=True, blank=True)
|
||||
average_rating = models.DecimalField(max_digits=3, decimal_places=2, null=True, blank=True)
|
||||
|
||||
# Additional ride classification
|
||||
ride_sub_type = models.CharField(
|
||||
max_length=100,
|
||||
blank=True,
|
||||
help_text="Sub-category of ride (e.g., 'Flying Coaster', 'Inverted Coaster', 'Log Flume')",
|
||||
)
|
||||
age_requirement = models.PositiveIntegerField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Minimum age requirement in years (if any)",
|
||||
)
|
||||
|
||||
# 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)
|
||||
@@ -680,6 +706,14 @@ class Ride(StateMachineMixin, TrackedModel):
|
||||
|
||||
self.save()
|
||||
|
||||
@property
|
||||
def is_closing(self) -> bool:
|
||||
"""Returns True if this ride has a closing date in the future (announced closure)."""
|
||||
from django.utils import timezone
|
||||
if self.closing_date:
|
||||
return self.closing_date > timezone.now().date()
|
||||
return False
|
||||
|
||||
def save(self, *args, **kwargs) -> None:
|
||||
# Handle slug generation and conflicts
|
||||
if not self.slug:
|
||||
|
||||
@@ -224,3 +224,152 @@ class FlatRideStats(TrackedModel):
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Flat Ride Stats for {self.ride.name}"
|
||||
|
||||
|
||||
# Transport Type Choices for Transportation Rides
|
||||
TRANSPORT_TYPES = [
|
||||
("TRAIN", "Train"),
|
||||
("MONORAIL", "Monorail"),
|
||||
("SKYLIFT", "Skylift / Chairlift"),
|
||||
("FERRY", "Ferry / Boat"),
|
||||
("PEOPLEMOVER", "PeopleMover"),
|
||||
("CABLE_CAR", "Cable Car"),
|
||||
("TRAM", "Tram"),
|
||||
]
|
||||
|
||||
|
||||
@pghistory.track()
|
||||
class KiddieRideStats(TrackedModel):
|
||||
"""
|
||||
Statistics specific to kiddie rides (category=KR).
|
||||
|
||||
Tracks age-appropriate ride characteristics and theming.
|
||||
"""
|
||||
|
||||
ride = models.OneToOneField(
|
||||
"rides.Ride",
|
||||
on_delete=models.CASCADE,
|
||||
related_name="kiddie_stats",
|
||||
help_text="Ride these kiddie ride statistics belong to",
|
||||
)
|
||||
|
||||
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 theme if applicable (e.g., 'Dinosaurs', 'Space')",
|
||||
)
|
||||
|
||||
character_theme = models.CharField(
|
||||
max_length=200,
|
||||
blank=True,
|
||||
help_text="Character theme if applicable (e.g., 'Paw Patrol', 'Peppa Pig')",
|
||||
)
|
||||
|
||||
guardian_required = models.BooleanField(
|
||||
default=False,
|
||||
help_text="Whether a guardian must be present during the ride",
|
||||
)
|
||||
|
||||
adult_ride_along = models.BooleanField(
|
||||
default=True,
|
||||
help_text="Whether adults can ride along with children",
|
||||
)
|
||||
|
||||
seats_per_vehicle = models.PositiveIntegerField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Number of seats per ride vehicle",
|
||||
)
|
||||
|
||||
class Meta(TrackedModel.Meta):
|
||||
verbose_name = "Kiddie Ride Statistics"
|
||||
verbose_name_plural = "Kiddie Ride Statistics"
|
||||
ordering = ["ride"]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Kiddie Ride Stats for {self.ride.name}"
|
||||
|
||||
|
||||
@pghistory.track()
|
||||
class TransportationStats(TrackedModel):
|
||||
"""
|
||||
Statistics specific to transportation rides (category=TR).
|
||||
|
||||
Tracks route, capacity, and vehicle information.
|
||||
"""
|
||||
|
||||
ride = models.OneToOneField(
|
||||
"rides.Ride",
|
||||
on_delete=models.CASCADE,
|
||||
related_name="transport_stats",
|
||||
help_text="Ride these transportation statistics belong to",
|
||||
)
|
||||
|
||||
transport_type = models.CharField(
|
||||
max_length=20,
|
||||
choices=TRANSPORT_TYPES,
|
||||
default="TRAIN",
|
||||
help_text="Type of transportation",
|
||||
)
|
||||
|
||||
route_length_ft = models.DecimalField(
|
||||
max_digits=8,
|
||||
decimal_places=2,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Total route length in feet",
|
||||
)
|
||||
|
||||
stations_count = models.PositiveIntegerField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Number of stations/stops on the route",
|
||||
)
|
||||
|
||||
vehicle_capacity = models.PositiveIntegerField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Passenger capacity per vehicle",
|
||||
)
|
||||
|
||||
vehicles_count = models.PositiveIntegerField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Total number of vehicles in operation",
|
||||
)
|
||||
|
||||
round_trip_duration_minutes = models.PositiveIntegerField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Duration of a complete round trip in minutes",
|
||||
)
|
||||
|
||||
scenic_highlights = models.TextField(
|
||||
blank=True,
|
||||
help_text="Notable scenic views or attractions along the route",
|
||||
)
|
||||
|
||||
is_one_way = models.BooleanField(
|
||||
default=False,
|
||||
help_text="Whether this is a one-way transportation (vs round-trip)",
|
||||
)
|
||||
|
||||
class Meta(TrackedModel.Meta):
|
||||
verbose_name = "Transportation Statistics"
|
||||
verbose_name_plural = "Transportation Statistics"
|
||||
ordering = ["ride"]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Transportation Stats for {self.ride.name}"
|
||||
|
||||
@@ -235,3 +235,46 @@ def update_ride_search_text_on_ride_model_change(sender, instance, **kwargs):
|
||||
update_ride_search_text(ride)
|
||||
except Exception as e:
|
||||
logger.exception(f"Failed to update ride search_text on ride model change: {e}")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Automatic Name History Tracking
|
||||
# =============================================================================
|
||||
|
||||
|
||||
@receiver(pre_save, sender=Ride)
|
||||
def track_ride_name_changes(sender, instance, **kwargs):
|
||||
"""
|
||||
Automatically create RideNameHistory when a ride's name changes.
|
||||
|
||||
This ensures versioning is automatic - when a ride is renamed,
|
||||
the previous name is preserved in the name history.
|
||||
"""
|
||||
if not instance.pk:
|
||||
return # Skip new rides
|
||||
|
||||
try:
|
||||
old_instance = Ride.objects.get(pk=instance.pk)
|
||||
|
||||
if old_instance.name != instance.name:
|
||||
from .models import RideNameHistory
|
||||
|
||||
current_year = timezone.now().year
|
||||
|
||||
# Create history entry for the old name
|
||||
RideNameHistory.objects.create(
|
||||
ride=instance,
|
||||
former_name=old_instance.name,
|
||||
to_year=current_year,
|
||||
reason="Name changed",
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"Ride {instance.pk} name changed from '{old_instance.name}' "
|
||||
f"to '{instance.name}' - history entry created"
|
||||
)
|
||||
except Ride.DoesNotExist:
|
||||
pass # New ride, no history to track
|
||||
except Exception as e:
|
||||
logger.exception(f"Failed to track name change for ride {instance.pk}: {e}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user