diff --git a/parks/migrations/0001_initial.py b/parks/migrations/0001_initial.py index 8c5cb684..7a04f607 100644 --- a/parks/migrations/0001_initial.py +++ b/parks/migrations/0001_initial.py @@ -86,16 +86,16 @@ class Migration(migrations.Migration): ("closing_date", models.DateField(blank=True, null=True)), ("created_at", models.DateTimeField(auto_now_add=True, null=True)), ("updated_at", models.DateTimeField(auto_now=True)), + ( "park", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="areas", to=PARKS_APP_MODEL, ), - ), ), ], - options = { + options={ "ordering": ["name"], }, ), @@ -123,7 +123,6 @@ class Migration(migrations.Migration): ), ), ( - "pgh_context", "pgh_context", models.ForeignKey( db_constraint=False, @@ -216,12 +215,12 @@ class Migration(migrations.Migration): ), ( "pgh_obj", + models.ForeignKey( db_constraint=False, on_delete=django.db.models.deletion.DO_NOTHING, related_name="events", to=PARKS_APP_MODEL, ), - ), ), ], options={ diff --git a/parks/migrations/0002_fix_pghistory_fields.py b/parks/migrations/0002_fix_pghistory_fields.py new file mode 100644 index 00000000..5c5ab8fa --- /dev/null +++ b/parks/migrations/0002_fix_pghistory_fields.py @@ -0,0 +1,35 @@ +# Generated by Django 5.1.4 on 2025-02-10 09:30 + +from django.db import migrations, models +import django.db.models.deletion + +class Migration(migrations.Migration): + dependencies = [ + ('pghistory', '0006_delete_aggregateevent'), + ('parks', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='parkevent', + 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.AlterField( + model_name='parkareaevent', + name='pgh_context', + field=models.ForeignKey( + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name='+', + to='pghistory.context', + ), + ), + ] \ No newline at end of file diff --git a/parks/urls.py b/parks/urls.py index 28828577..aa6e18e6 100644 --- a/parks/urls.py +++ b/parks/urls.py @@ -36,6 +36,6 @@ urlpatterns = [ path("/transports/", ParkSingleCategoryListView.as_view(), {'category': 'TR'}, name="park_transports"), path("/others/", ParkSingleCategoryListView.as_view(), {'category': 'OT'}, name="park_others"), - # Include rides URLs with park_slug - path("/rides/", include("rides.urls", namespace="rides")), + # Include park-specific rides URLs + path("/rides/", include("rides.park_urls", namespace="rides")), ] diff --git a/rides/migrations/0001_initial.py b/rides/migrations/0001_initial.py index 3aa6a8ad..93cfc344 100644 --- a/rides/migrations/0001_initial.py +++ b/rides/migrations/0001_initial.py @@ -1,20 +1,15 @@ -# Generated by Django 5.1.4 on 2025-02-10 01:26 +# Generated by Django 5.1.4 on 2025-02-10 09:31 import django.db.models.deletion -import pgtrigger.compiler -import pgtrigger.migrations from django.db import migrations, models - class Migration(migrations.Migration): - initial = True dependencies = [ ("companies", "0001_initial"), ("designers", "0001_initial"), - ("parks", "0001_initial"), - ("pghistory", "0006_delete_aggregateevent"), + ("parks", "0001_initial"), # Changed to depend on initial parks migration ] operations = [ @@ -76,14 +71,8 @@ class Migration(migrations.Migration): ("status_since", models.DateField(blank=True, null=True)), ("min_height_in", models.PositiveIntegerField(blank=True, null=True)), ("max_height_in", models.PositiveIntegerField(blank=True, null=True)), - ( - "capacity_per_hour", - models.PositiveIntegerField(blank=True, null=True), - ), - ( - "ride_duration_seconds", - models.PositiveIntegerField(blank=True, null=True), - ), + ("capacity_per_hour", models.PositiveIntegerField(blank=True, null=True)), + ("ride_duration_seconds", models.PositiveIntegerField(blank=True, null=True)), ( "average_rating", models.DecimalField( @@ -134,451 +123,4 @@ class Migration(migrations.Migration): "ordering": ["name"], }, ), - migrations.CreateModel( - name="RideModel", - fields=[ - ("id", models.BigAutoField(primary_key=True, serialize=False)), - ("name", models.CharField(max_length=255)), - ("description", models.TextField(blank=True)), - ( - "category", - models.CharField( - blank=True, - choices=[ - ("", "Select ride type"), - ("RC", "Roller Coaster"), - ("DR", "Dark Ride"), - ("FR", "Flat Ride"), - ("WR", "Water Ride"), - ("TR", "Transport"), - ("OT", "Other"), - ], - default="", - max_length=2, - ), - ), - ("created_at", models.DateTimeField(auto_now_add=True)), - ("updated_at", models.DateTimeField(auto_now=True)), - ( - "manufacturer", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="ride_models", - to="companies.manufacturer", - ), - ), - ], - options={ - "ordering": ["manufacturer", "name"], - "unique_together": {("manufacturer", "name")}, - }, - ), - migrations.CreateModel( - name="RideEvent", - 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()), - ("name", models.CharField(max_length=255)), - ("slug", models.SlugField(db_index=False, max_length=255)), - ("description", models.TextField(blank=True)), - ( - "category", - models.CharField( - blank=True, - choices=[ - ("", "Select ride type"), - ("RC", "Roller Coaster"), - ("DR", "Dark Ride"), - ("FR", "Flat Ride"), - ("WR", "Water Ride"), - ("TR", "Transport"), - ("OT", "Other"), - ], - default="", - max_length=2, - ), - ), - ( - "status", - models.CharField( - choices=[ - ("OPERATING", "Operating"), - ("SBNO", "Standing But Not Operating"), - ("CLOSING", "Closing"), - ("CLOSED_PERM", "Permanently Closed"), - ("UNDER_CONSTRUCTION", "Under Construction"), - ("DEMOLISHED", "Demolished"), - ("RELOCATED", "Relocated"), - ], - default="OPERATING", - max_length=20, - ), - ), - ( - "post_closing_status", - models.CharField( - blank=True, - choices=[ - ("SBNO", "Standing But Not Operating"), - ("CLOSED_PERM", "Permanently Closed"), - ], - help_text="Status to change to after closing date", - max_length=20, - null=True, - ), - ), - ("opening_date", models.DateField(blank=True, null=True)), - ("closing_date", models.DateField(blank=True, null=True)), - ("status_since", models.DateField(blank=True, null=True)), - ("min_height_in", models.PositiveIntegerField(blank=True, null=True)), - ("max_height_in", models.PositiveIntegerField(blank=True, null=True)), - ( - "capacity_per_hour", - models.PositiveIntegerField(blank=True, null=True), - ), - ( - "ride_duration_seconds", - models.PositiveIntegerField(blank=True, null=True), - ), - ( - "average_rating", - models.DecimalField( - blank=True, decimal_places=2, max_digits=3, null=True - ), - ), - ("created_at", models.DateTimeField(auto_now_add=True)), - ("updated_at", models.DateTimeField(auto_now=True)), - ( - "designer", - models.ForeignKey( - blank=True, - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - related_name="+", - related_query_name="+", - to="designers.designer", - ), - ), - ( - "manufacturer", - models.ForeignKey( - blank=True, - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - related_name="+", - related_query_name="+", - to="companies.manufacturer", - ), - ), - ( - "park", - models.ForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.DO_NOTHING, - related_name="+", - related_query_name="+", - to="parks.park", - ), - ), - ( - "park_area", - models.ForeignKey( - blank=True, - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - related_name="+", - related_query_name="+", - to="parks.parkarea", - ), - ), - ( - "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.ride", - ), - ), - ( - "ride_model", - models.ForeignKey( - blank=True, - db_constraint=False, - help_text="The specific model/type of this ride", - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - related_name="+", - related_query_name="+", - to="rides.ridemodel", - ), - ), - ], - options={ - "abstract": False, - }, - ), - migrations.AddField( - model_name="ride", - name="ride_model", - field=models.ForeignKey( - blank=True, - help_text="The specific model/type of this ride", - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="rides", - to="rides.ridemodel", - ), - ), - migrations.CreateModel( - name="RideModelEvent", - 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()), - ("name", models.CharField(max_length=255)), - ("description", models.TextField(blank=True)), - ( - "category", - models.CharField( - blank=True, - choices=[ - ("", "Select ride type"), - ("RC", "Roller Coaster"), - ("DR", "Dark Ride"), - ("FR", "Flat Ride"), - ("WR", "Water Ride"), - ("TR", "Transport"), - ("OT", "Other"), - ], - default="", - max_length=2, - ), - ), - ("created_at", models.DateTimeField(auto_now_add=True)), - ("updated_at", models.DateTimeField(auto_now=True)), - ( - "manufacturer", - models.ForeignKey( - blank=True, - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - related_name="+", - related_query_name="+", - to="companies.manufacturer", - ), - ), - ( - "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.ridemodel", - ), - ), - ], - options={ - "abstract": False, - }, - ), - migrations.CreateModel( - name="RollerCoasterStats", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "height_ft", - models.DecimalField( - blank=True, decimal_places=2, max_digits=6, null=True - ), - ), - ( - "length_ft", - models.DecimalField( - blank=True, decimal_places=2, max_digits=7, null=True - ), - ), - ( - "speed_mph", - models.DecimalField( - blank=True, decimal_places=2, max_digits=5, null=True - ), - ), - ("inversions", models.PositiveIntegerField(default=0)), - ( - "ride_time_seconds", - models.PositiveIntegerField(blank=True, null=True), - ), - ("track_type", models.CharField(blank=True, max_length=255)), - ( - "track_material", - models.CharField( - blank=True, - choices=[ - ("STEEL", "Steel"), - ("WOOD", "Wood"), - ("HYBRID", "Hybrid"), - ], - default="STEEL", - max_length=20, - ), - ), - ( - "roller_coaster_type", - models.CharField( - blank=True, - choices=[ - ("SITDOWN", "Sit Down"), - ("INVERTED", "Inverted"), - ("FLYING", "Flying"), - ("STANDUP", "Stand Up"), - ("WING", "Wing"), - ("DIVE", "Dive"), - ("FAMILY", "Family"), - ("WILD_MOUSE", "Wild Mouse"), - ("SPINNING", "Spinning"), - ("FOURTH_DIMENSION", "4th Dimension"), - ("OTHER", "Other"), - ], - default="SITDOWN", - max_length=20, - ), - ), - ( - "max_drop_height_ft", - models.DecimalField( - blank=True, decimal_places=2, max_digits=6, null=True - ), - ), - ( - "launch_type", - models.CharField( - choices=[ - ("CHAIN", "Chain Lift"), - ("LSM", "LSM Launch"), - ("HYDRAULIC", "Hydraulic Launch"), - ("GRAVITY", "Gravity"), - ("OTHER", "Other"), - ], - default="CHAIN", - max_length=20, - ), - ), - ("train_style", models.CharField(blank=True, max_length=255)), - ("trains_count", models.PositiveIntegerField(blank=True, null=True)), - ("cars_per_train", models.PositiveIntegerField(blank=True, null=True)), - ("seats_per_car", models.PositiveIntegerField(blank=True, null=True)), - ( - "ride", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="coaster_stats", - to="rides.ride", - ), - ), - ], - options={ - "verbose_name": "Roller Coaster Statistics", - "verbose_name_plural": "Roller Coaster Statistics", - }, - ), - 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", "id", "manufacturer_id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "updated_at") VALUES (NEW."category", NEW."created_at", NEW."description", NEW."id", NEW."manufacturer_id", NEW."name", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."updated_at"); RETURN NULL;', - hash="[AWS-SECRET-REMOVED]", - 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", "id", "manufacturer_id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "updated_at") VALUES (NEW."category", NEW."created_at", NEW."description", NEW."id", NEW."manufacturer_id", NEW."name", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."updated_at"); RETURN NULL;', - hash="[AWS-SECRET-REMOVED]", - operation="UPDATE", - pgid="pgtrigger_update_update_0ca1a", - table="rides_ridemodel", - when="AFTER", - ), - ), - ), - migrations.AlterUniqueTogether( - name="ride", - unique_together={("park", "slug")}, - ), - pgtrigger.migrations.AddTrigger( - model_name="ride", - trigger=pgtrigger.compiler.Trigger( - name="insert_insert", - sql=pgtrigger.compiler.UpsertTriggerSql( - func='INSERT INTO "rides_rideevent" ("average_rating", "capacity_per_hour", "category", "closing_date", "created_at", "description", "designer_id", "id", "manufacturer_id", "max_height_in", "min_height_in", "name", "opening_date", "park_area_id", "park_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "post_closing_status", "ride_duration_seconds", "ride_model_id", "slug", "status", "status_since", "updated_at") VALUES (NEW."average_rating", NEW."capacity_per_hour", NEW."category", NEW."closing_date", 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."park_area_id", NEW."park_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."post_closing_status", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."slug", NEW."status", NEW."status_since", NEW."updated_at"); RETURN NULL;', - hash="[AWS-SECRET-REMOVED]", - 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", "capacity_per_hour", "category", "closing_date", "created_at", "description", "designer_id", "id", "manufacturer_id", "max_height_in", "min_height_in", "name", "opening_date", "park_area_id", "park_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "post_closing_status", "ride_duration_seconds", "ride_model_id", "slug", "status", "status_since", "updated_at") VALUES (NEW."average_rating", NEW."capacity_per_hour", NEW."category", NEW."closing_date", 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."park_area_id", NEW."park_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."post_closing_status", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."slug", NEW."status", NEW."status_since", NEW."updated_at"); RETURN NULL;', - hash="[AWS-SECRET-REMOVED]", - operation="UPDATE", - pgid="pgtrigger_update_update_4917a", - table="rides_ride", - when="AFTER", - ), - ), - ), ] diff --git a/rides/migrations/0002_ridemodel.py b/rides/migrations/0002_ridemodel.py new file mode 100644 index 00000000..ad44f137 --- /dev/null +++ b/rides/migrations/0002_ridemodel.py @@ -0,0 +1,66 @@ +# Generated by Django 5.1.4 on 2025-02-10 09:31 + +import django.db.models.deletion +from django.db import migrations, models + +class Migration(migrations.Migration): + dependencies = [ + ("companies", "0001_initial"), + ("rides", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="RideModel", + fields=[ + ("id", models.BigAutoField(primary_key=True, serialize=False)), + ("name", models.CharField(max_length=255)), + ("description", models.TextField(blank=True)), + ( + "category", + models.CharField( + blank=True, + choices=[ + ("", "Select ride type"), + ("RC", "Roller Coaster"), + ("DR", "Dark Ride"), + ("FR", "Flat Ride"), + ("WR", "Water Ride"), + ("TR", "Transport"), + ("OT", "Other"), + ], + default="", + max_length=2, + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "manufacturer", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="ride_models", + to="companies.manufacturer", + ), + ), + ], + options={ + "ordering": ["manufacturer", "name"], + "unique_together": {("manufacturer", "name")}, + }, + ), + migrations.AddField( + model_name="ride", + name="ride_model", + field=models.ForeignKey( + blank=True, + help_text="The specific model/type of this ride", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="rides", + to="rides.ridemodel", + ), + ), + ] \ No newline at end of file diff --git a/rides/migrations/0003_history_tracking.py b/rides/migrations/0003_history_tracking.py new file mode 100644 index 00000000..f8e8fd8f --- /dev/null +++ b/rides/migrations/0003_history_tracking.py @@ -0,0 +1,294 @@ +# Generated by Django 5.1.4 on 2025-02-10 09:32 + +import django.db.models.deletion +import pgtrigger.compiler +import pgtrigger.migrations +from django.db import migrations, models + +class Migration(migrations.Migration): + dependencies = [ + ("designers", "0001_initial"), + ("companies", "0001_initial"), + ("parks", "0002_fix_pghistory_fields"), # This dependency is important for pghistory fields + ("pghistory", "0006_delete_aggregateevent"), + ("rides", "0002_ridemodel"), + ] + + operations = [ + migrations.CreateModel( + name="RideEvent", + 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()), + ("name", models.CharField(max_length=255)), + ("slug", models.SlugField(db_index=False, max_length=255)), + ("description", models.TextField(blank=True)), + ( + "category", + models.CharField( + blank=True, + choices=[ + ("", "Select ride type"), + ("RC", "Roller Coaster"), + ("DR", "Dark Ride"), + ("FR", "Flat Ride"), + ("WR", "Water Ride"), + ("TR", "Transport"), + ("OT", "Other"), + ], + default="", + max_length=2, + ), + ), + ( + "status", + models.CharField( + choices=[ + ("OPERATING", "Operating"), + ("SBNO", "Standing But Not Operating"), + ("CLOSING", "Closing"), + ("CLOSED_PERM", "Permanently Closed"), + ("UNDER_CONSTRUCTION", "Under Construction"), + ("DEMOLISHED", "Demolished"), + ("RELOCATED", "Relocated"), + ], + default="OPERATING", + max_length=20, + ), + ), + ( + "post_closing_status", + models.CharField( + blank=True, + choices=[ + ("SBNO", "Standing But Not Operating"), + ("CLOSED_PERM", "Permanently Closed"), + ], + help_text="Status to change to after closing date", + max_length=20, + null=True, + ), + ), + ("opening_date", models.DateField(blank=True, null=True)), + ("closing_date", models.DateField(blank=True, null=True)), + ("status_since", models.DateField(blank=True, null=True)), + ("min_height_in", models.PositiveIntegerField(blank=True, null=True)), + ("max_height_in", models.PositiveIntegerField(blank=True, null=True)), + ("capacity_per_hour", models.PositiveIntegerField(blank=True, null=True)), + ("ride_duration_seconds", models.PositiveIntegerField(blank=True, null=True)), + ( + "average_rating", + models.DecimalField( + blank=True, decimal_places=2, max_digits=3, null=True + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "designer", + models.ForeignKey( + blank=True, + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + related_query_name="+", + to="designers.designer", + ), + ), + ( + "manufacturer", + models.ForeignKey( + blank=True, + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + related_query_name="+", + to="companies.manufacturer", + ), + ), + ( + "park", + models.ForeignKey( + db_constraint=False, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + related_query_name="+", + to="parks.park", + ), + ), + ( + "park_area", + models.ForeignKey( + blank=True, + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + related_query_name="+", + to="parks.parkarea", + ), + ), + ( + "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.ride", + ), + ), + ( + "ride_model", + models.ForeignKey( + blank=True, + db_constraint=False, + help_text="The specific model/type of this ride", + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + related_query_name="+", + to="rides.ridemodel", + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="RideModelEvent", + 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()), + ("name", models.CharField(max_length=255)), + ("description", models.TextField(blank=True)), + ( + "category", + models.CharField( + blank=True, + choices=[ + ("", "Select ride type"), + ("RC", "Roller Coaster"), + ("DR", "Dark Ride"), + ("FR", "Flat Ride"), + ("WR", "Water Ride"), + ("TR", "Transport"), + ("OT", "Other"), + ], + default="", + max_length=2, + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "manufacturer", + models.ForeignKey( + blank=True, + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + related_query_name="+", + to="companies.manufacturer", + ), + ), + ( + "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.ridemodel", + ), + ), + ], + options={ + "abstract": False, + }, + ), + 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", "id", "manufacturer_id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "updated_at") VALUES (NEW."category", NEW."created_at", NEW."description", NEW."id", NEW."manufacturer_id", NEW."name", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."updated_at"); RETURN NULL;', + hash="[AWS-SECRET-REMOVED]", + 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", "id", "manufacturer_id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "updated_at") VALUES (NEW."category", NEW."created_at", NEW."description", NEW."id", NEW."manufacturer_id", NEW."name", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."updated_at"); RETURN NULL;', + hash="[AWS-SECRET-REMOVED]", + operation="UPDATE", + pgid="pgtrigger_update_update_0ca1a", + table="rides_ridemodel", + when="AFTER", + ), + ), + ), + pgtrigger.migrations.AddTrigger( + model_name="ride", + trigger=pgtrigger.compiler.Trigger( + name="insert_insert", + sql=pgtrigger.compiler.UpsertTriggerSql( + func='INSERT INTO "rides_rideevent" ("average_rating", "capacity_per_hour", "category", "closing_date", "created_at", "description", "designer_id", "id", "manufacturer_id", "max_height_in", "min_height_in", "name", "opening_date", "park_area_id", "park_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "post_closing_status", "ride_duration_seconds", "ride_model_id", "slug", "status", "status_since", "updated_at") VALUES (NEW."average_rating", NEW."capacity_per_hour", NEW."category", NEW."closing_date", 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."park_area_id", NEW."park_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."post_closing_status", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."slug", NEW."status", NEW."status_since", NEW."updated_at"); RETURN NULL;', + hash="[AWS-SECRET-REMOVED]", + 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", "capacity_per_hour", "category", "closing_date", "created_at", "description", "designer_id", "id", "manufacturer_id", "max_height_in", "min_height_in", "name", "opening_date", "park_area_id", "park_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "post_closing_status", "ride_duration_seconds", "ride_model_id", "slug", "status", "status_since", "updated_at") VALUES (NEW."average_rating", NEW."capacity_per_hour", NEW."category", NEW."closing_date", 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."park_area_id", NEW."park_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."post_closing_status", NEW."ride_duration_seconds", NEW."ride_model_id", NEW."slug", NEW."status", NEW."status_since", NEW."updated_at"); RETURN NULL;', + hash="[AWS-SECRET-REMOVED]", + operation="UPDATE", + pgid="pgtrigger_update_update_4917a", + table="rides_ride", + when="AFTER", + ), + ), + ), + ] \ No newline at end of file diff --git a/rides/migrations/0004_rollercoasterstats.py b/rides/migrations/0004_rollercoasterstats.py new file mode 100644 index 00000000..b4511312 --- /dev/null +++ b/rides/migrations/0004_rollercoasterstats.py @@ -0,0 +1,120 @@ +# Generated by Django 5.1.4 on 2025-02-10 09:33 + +import django.db.models.deletion +from django.db import migrations, models + +class Migration(migrations.Migration): + dependencies = [ + ("rides", "0003_history_tracking"), + ] + + operations = [ + migrations.CreateModel( + name="RollerCoasterStats", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "height_ft", + models.DecimalField( + blank=True, decimal_places=2, max_digits=6, null=True + ), + ), + ( + "length_ft", + models.DecimalField( + blank=True, decimal_places=2, max_digits=7, null=True + ), + ), + ( + "speed_mph", + models.DecimalField( + blank=True, decimal_places=2, max_digits=5, null=True + ), + ), + ("inversions", models.PositiveIntegerField(default=0)), + ( + "ride_time_seconds", + models.PositiveIntegerField(blank=True, null=True), + ), + ("track_type", models.CharField(blank=True, max_length=255)), + ( + "track_material", + models.CharField( + blank=True, + choices=[ + ("STEEL", "Steel"), + ("WOOD", "Wood"), + ("HYBRID", "Hybrid"), + ], + default="STEEL", + max_length=20, + ), + ), + ( + "roller_coaster_type", + models.CharField( + blank=True, + choices=[ + ("SITDOWN", "Sit Down"), + ("INVERTED", "Inverted"), + ("FLYING", "Flying"), + ("STANDUP", "Stand Up"), + ("WING", "Wing"), + ("DIVE", "Dive"), + ("FAMILY", "Family"), + ("WILD_MOUSE", "Wild Mouse"), + ("SPINNING", "Spinning"), + ("FOURTH_DIMENSION", "4th Dimension"), + ("OTHER", "Other"), + ], + default="SITDOWN", + max_length=20, + ), + ), + ( + "max_drop_height_ft", + models.DecimalField( + blank=True, decimal_places=2, max_digits=6, null=True + ), + ), + ( + "launch_type", + models.CharField( + choices=[ + ("CHAIN", "Chain Lift"), + ("LSM", "LSM Launch"), + ("HYDRAULIC", "Hydraulic Launch"), + ("GRAVITY", "Gravity"), + ("OTHER", "Other"), + ], + default="CHAIN", + max_length=20, + ), + ), + ("train_style", models.CharField(blank=True, max_length=255)), + ("trains_count", models.PositiveIntegerField(blank=True, null=True)), + ("cars_per_train", models.PositiveIntegerField(blank=True, null=True)), + ("seats_per_car", models.PositiveIntegerField(blank=True, null=True)), + ( + "ride", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="coaster_stats", + to="rides.ride", + ), + ), + ], + options={ + "verbose_name": "Roller Coaster Statistics", + "verbose_name_plural": "Roller Coaster Statistics", + }, + ), + ] \ No newline at end of file diff --git a/rides/migrations/0005_fix_event_context_fields.py b/rides/migrations/0005_fix_event_context_fields.py new file mode 100644 index 00000000..30a266b5 --- /dev/null +++ b/rides/migrations/0005_fix_event_context_fields.py @@ -0,0 +1,35 @@ +# Generated by Django 5.1.4 on 2025-02-10 10:38 + +import django.db.models.deletion +from django.db import migrations, models + +class Migration(migrations.Migration): + dependencies = [ + ("pghistory", "0006_delete_aggregateevent"), + ("rides", "0004_rollercoasterstats"), + ] + + operations = [ + migrations.AlterField( + model_name="rideevent", + 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.AlterField( + model_name="ridemodelevent", + name="pgh_context", + field=models.ForeignKey( + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + to="pghistory.context", + ), + ), + ] \ No newline at end of file diff --git a/rides/models.py b/rides/models.py index 7fa852c1..998edbbc 100644 --- a/rides/models.py +++ b/rides/models.py @@ -50,7 +50,13 @@ class RideEvent(models.Model, DiffMixin): # Context fields pgh_obj = models.ForeignKey('Ride', on_delete=models.CASCADE) - pgh_context = models.JSONField(null=True) + pgh_context = models.ForeignKey( + 'pghistory.Context', + on_delete=models.DO_NOTHING, + db_constraint=False, + related_name='+', + null=True, + ) class Meta: db_table = 'rides_rideevent' @@ -80,7 +86,13 @@ class RideModelEvent(models.Model, DiffMixin): # Context fields pgh_obj = models.ForeignKey('RideModel', on_delete=models.CASCADE) - pgh_context = models.JSONField(null=True) + pgh_context = models.ForeignKey( + 'pghistory.Context', + on_delete=models.DO_NOTHING, + db_constraint=False, + related_name='+', + null=True, + ) class Meta: db_table = 'rides_ridemodelevent' diff --git a/rides/park_urls.py b/rides/park_urls.py new file mode 100644 index 00000000..4ec779f3 --- /dev/null +++ b/rides/park_urls.py @@ -0,0 +1,46 @@ +from django.urls import path +from . import views + +app_name = "rides" + +urlpatterns = [ + # Park-specific list views + path("", views.RideListView.as_view(), name="ride_list"), + path("create/", views.RideCreateView.as_view(), name="ride_create"), + + # Park-specific detail views + path( + "/", + views.RideDetailView.as_view(), + name="ride_detail" + ), + path( + "/update/", + views.RideUpdateView.as_view(), + name="ride_update" + ), + + # Search endpoints + path( + "search/manufacturers/", + views.search_manufacturers, + name="search_manufacturers" + ), + path( + "search/designers/", + views.search_designers, + name="search_designers" + ), + path( + "search/models/", + views.search_ride_models, + name="search_ride_models" + ), + + # HTMX endpoints + path( + "coaster-fields/", + views.show_coaster_fields, + name="coaster_fields" + ), +] \ No newline at end of file diff --git a/rides/urls.py b/rides/urls.py index d83b7482..b5df1f47 100644 --- a/rides/urls.py +++ b/rides/urls.py @@ -4,59 +4,85 @@ from . import views app_name = "rides" urlpatterns = [ - # List views - path("", views.RideListView.as_view(), name="ride_list"), - path("create/", views.RideCreateView.as_view(), name="ride_create"), + # Global list views + path("", views.RideListView.as_view(), name="global_ride_list"), - # Search endpoints - path( - "search/manufacturers/", views.search_manufacturers, name="search_manufacturers" - ), - path("search/designers/", views.search_designers, name="search_designers"), - path("search/models/", views.search_ride_models, name="search_ride_models"), - - # HTMX endpoints - path("coaster-fields/", views.show_coaster_fields, name="coaster_fields"), - - # Category views for global listing + # Global category views path( "roller_coasters/", views.SingleCategoryListView.as_view(), {"category": "RC"}, - name="roller_coasters", + name="global_roller_coasters", ), path( "dark_rides/", views.SingleCategoryListView.as_view(), {"category": "DR"}, - name="dark_rides", + name="global_dark_rides", ), path( "flat_rides/", views.SingleCategoryListView.as_view(), {"category": "FR"}, - name="flat_rides", + name="global_flat_rides", ), path( "water_rides/", views.SingleCategoryListView.as_view(), {"category": "WR"}, - name="water_rides", + name="global_water_rides", ), path( "transports/", views.SingleCategoryListView.as_view(), {"category": "TR"}, - name="transports", + name="global_transports", ), path( "others/", views.SingleCategoryListView.as_view(), {"category": "OT"}, - name="others", + name="global_others", + ), + + # Park-specific URLs + path( + "create/", + views.RideCreateView.as_view(), + name="ride_create" + ), + path( + "/", + views.RideDetailView.as_view(), + name="ride_detail" + ), + path( + "/update/", + views.RideUpdateView.as_view(), + name="ride_update" ), - # Detail and update views - must come after category views - path("/", views.RideDetailView.as_view(), name="ride_detail"), - path("/update/", views.RideUpdateView.as_view(), name="ride_update"), + # Search endpoints + path( + "search/manufacturers/", + views.search_manufacturers, + name="search_manufacturers" + ), + path( + "search/designers/", + views.search_designers, + name="search_designers" + ), + path( + "search/models/", + views.search_ride_models, + name="search_ride_models" + ), + + # HTMX endpoints + path( + "coaster-fields/", + views.show_coaster_fields, + name="coaster_fields" + ), ] diff --git a/thrillwiki/urls.py b/thrillwiki/urls.py index c0228498..e8bbcd56 100644 --- a/thrillwiki/urls.py +++ b/thrillwiki/urls.py @@ -13,9 +13,9 @@ urlpatterns = [ path("admin/", admin.site.urls), # Main app URLs path("", HomeView.as_view(), name="home"), - # Parks URLs + # Parks and Rides URLs path("parks/", include("parks.urls", namespace="parks")), - # Rides URLs + # Global rides URLs path("rides/", include("rides.urls", namespace="rides")), # Other URLs path("reviews/", include("reviews.urls")),