mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 08:11:09 -05:00
major changes, including tailwind v4
This commit is contained in:
201
rides/admin.py
201
rides/admin.py
@@ -1,168 +1,73 @@
|
||||
from django.contrib import admin
|
||||
from django.utils.html import format_html
|
||||
from django.db.models import Avg
|
||||
from .models import Ride, RollerCoasterStats
|
||||
from django.contrib.gis.admin import GISModelAdmin
|
||||
from .models.company import Company
|
||||
from .models.rides import Ride
|
||||
from .models.location import RideLocation
|
||||
|
||||
class RollerCoasterStatsInline(admin.StackedInline):
|
||||
model = RollerCoasterStats
|
||||
can_delete = False
|
||||
class ManufacturerAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'headquarters', 'website', 'rides_count')
|
||||
search_fields = ('name',)
|
||||
|
||||
def get_queryset(self, request):
|
||||
return super().get_queryset(request).filter(roles__contains=['MANUFACTURER'])
|
||||
|
||||
class DesignerAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'headquarters', 'website')
|
||||
search_fields = ('name',)
|
||||
|
||||
def get_queryset(self, request):
|
||||
return super().get_queryset(request).filter(roles__contains=['DESIGNER'])
|
||||
|
||||
|
||||
class RideLocationInline(admin.StackedInline):
|
||||
"""Inline admin for RideLocation"""
|
||||
model = RideLocation
|
||||
extra = 0
|
||||
fieldsets = (
|
||||
('Basic Stats', {
|
||||
'fields': (
|
||||
('height_ft', 'length_ft'),
|
||||
('speed_mph', 'inversions'),
|
||||
'ride_time_seconds'
|
||||
)
|
||||
}),
|
||||
('Track Details', {
|
||||
'fields': (
|
||||
'track_type',
|
||||
'launch_type'
|
||||
)
|
||||
}),
|
||||
('Train Configuration', {
|
||||
'fields': (
|
||||
'train_style',
|
||||
('trains_count', 'cars_per_train', 'seats_per_car')
|
||||
)
|
||||
}),
|
||||
fields = (
|
||||
'park_area',
|
||||
'point',
|
||||
'entrance_notes',
|
||||
'accessibility_notes',
|
||||
)
|
||||
|
||||
@admin.register(Ride)
|
||||
class RideAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'name', 'park', 'category', 'get_status', 'manufacturer', 'opening_date', 'get_avg_rating')
|
||||
list_filter = ('status', 'category', 'manufacturer', 'park')
|
||||
search_fields = ('name', 'park__name', 'manufacturer__name', 'description')
|
||||
prepopulated_fields = {'slug': ('name',)}
|
||||
inlines = [RollerCoasterStatsInline]
|
||||
readonly_fields = ('id', 'created_at', 'updated_at')
|
||||
actions = ['mark_as_operating', 'mark_as_closed', 'mark_as_under_maintenance', 'mark_as_removed']
|
||||
|
||||
class RideLocationAdmin(GISModelAdmin):
|
||||
"""Admin for standalone RideLocation management"""
|
||||
list_display = ('ride', 'park_area', 'has_coordinates', 'created_at')
|
||||
list_filter = ('park_area', 'created_at')
|
||||
search_fields = ('ride__name', 'park_area', 'entrance_notes')
|
||||
readonly_fields = ('latitude', 'longitude', 'coordinates', 'created_at', 'updated_at')
|
||||
fieldsets = (
|
||||
('Basic Information', {
|
||||
'fields': (
|
||||
'name',
|
||||
'slug',
|
||||
'description',
|
||||
'park',
|
||||
'park_area'
|
||||
)
|
||||
('Ride', {
|
||||
'fields': ('ride',)
|
||||
}),
|
||||
('Ride Details', {
|
||||
'fields': (
|
||||
'category',
|
||||
'manufacturer',
|
||||
'model_name',
|
||||
'status'
|
||||
)
|
||||
('Location Information', {
|
||||
'fields': ('park_area', 'point', 'latitude', 'longitude', 'coordinates'),
|
||||
'description': 'Optional coordinates - not all rides need precise location tracking'
|
||||
}),
|
||||
('Dates', {
|
||||
'fields': (
|
||||
'opening_date',
|
||||
'closing_date',
|
||||
'status_since'
|
||||
)
|
||||
}),
|
||||
('Requirements', {
|
||||
'fields': (
|
||||
'min_height_in',
|
||||
'max_height_in',
|
||||
'accessibility_options'
|
||||
)
|
||||
}),
|
||||
('Capacity', {
|
||||
'fields': (
|
||||
'capacity_per_hour',
|
||||
'ride_duration_seconds'
|
||||
)
|
||||
('Navigation Notes', {
|
||||
'fields': ('entrance_notes', 'accessibility_notes'),
|
||||
}),
|
||||
('Metadata', {
|
||||
'fields': ('id', 'created_at', 'updated_at'),
|
||||
'fields': ('created_at', 'updated_at'),
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
)
|
||||
|
||||
def get_status(self, obj):
|
||||
status_colors = {
|
||||
'OPERATING': 'green',
|
||||
'CLOSED_TEMP': 'orange',
|
||||
'CLOSED_PERM': 'red',
|
||||
'UNDER_CONSTRUCTION': 'blue',
|
||||
'DEMOLISHED': 'grey',
|
||||
'RELOCATED': 'purple'
|
||||
}
|
||||
return format_html(
|
||||
'<span style="color: {};">{}</span>',
|
||||
status_colors.get(obj.status, 'black'),
|
||||
obj.get_status_display()
|
||||
)
|
||||
get_status.short_description = 'Status'
|
||||
def latitude(self, obj):
|
||||
return obj.latitude
|
||||
latitude.short_description = 'Latitude'
|
||||
|
||||
def get_avg_rating(self, obj):
|
||||
avg = obj.reviews.filter(is_published=True).aggregate(avg_rating=Avg('rating'))['avg_rating']
|
||||
if avg:
|
||||
rating_str = '{:.1f}'.format(float(avg))
|
||||
return format_html(
|
||||
'<span style="color: gold;">★ {}</span>',
|
||||
rating_str
|
||||
)
|
||||
return '-'
|
||||
get_avg_rating.short_description = 'Rating'
|
||||
def longitude(self, obj):
|
||||
return obj.longitude
|
||||
longitude.short_description = 'Longitude'
|
||||
|
||||
def mark_as_operating(self, request, queryset):
|
||||
queryset.update(status='OPERATING')
|
||||
mark_as_operating.short_description = "Mark selected rides as operating"
|
||||
|
||||
def mark_as_closed(self, request, queryset):
|
||||
queryset.update(status='CLOSED_TEMP')
|
||||
mark_as_closed.short_description = "Mark selected rides as temporarily closed"
|
||||
class RideAdmin(admin.ModelAdmin):
|
||||
"""Enhanced Ride admin with location inline"""
|
||||
inlines = [RideLocationInline]
|
||||
|
||||
def mark_as_under_maintenance(self, request, queryset):
|
||||
queryset.update(status='CLOSED_TEMP')
|
||||
mark_as_under_maintenance.short_description = "Mark selected rides as under maintenance"
|
||||
|
||||
def mark_as_removed(self, request, queryset):
|
||||
queryset.update(status='DEMOLISHED')
|
||||
mark_as_removed.short_description = "Mark selected rides as demolished"
|
||||
|
||||
@admin.register(RollerCoasterStats)
|
||||
class RollerCoasterStatsAdmin(admin.ModelAdmin):
|
||||
list_display = ('ride', 'height_ft', 'length_ft', 'speed_mph', 'inversions', 'get_capacity')
|
||||
list_filter = ('launch_type', 'track_type', 'train_style')
|
||||
search_fields = ('ride__name', 'track_type')
|
||||
readonly_fields = ('id', 'ride')
|
||||
|
||||
fieldsets = (
|
||||
('Basic Stats', {
|
||||
'fields': (
|
||||
'id',
|
||||
'ride',
|
||||
('height_ft', 'length_ft'),
|
||||
('speed_mph', 'inversions'),
|
||||
'ride_time_seconds'
|
||||
)
|
||||
}),
|
||||
('Track Details', {
|
||||
'fields': (
|
||||
'track_type',
|
||||
'launch_type'
|
||||
)
|
||||
}),
|
||||
('Train Configuration', {
|
||||
'fields': (
|
||||
'train_style',
|
||||
('trains_count', 'cars_per_train', 'seats_per_car')
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
def get_capacity(self, obj):
|
||||
if obj.trains_count and obj.cars_per_train and obj.seats_per_car:
|
||||
capacity = obj.trains_count * obj.cars_per_train * obj.seats_per_car
|
||||
return format_html(
|
||||
'{} seats total',
|
||||
str(capacity)
|
||||
)
|
||||
return '-'
|
||||
get_capacity.short_description = 'Total Capacity'
|
||||
admin.site.register(Company)
|
||||
admin.site.register(Ride, RideAdmin)
|
||||
admin.site.register(RideLocation, RideLocationAdmin)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
from django import forms
|
||||
from django.forms import ModelChoiceField
|
||||
from django.urls import reverse_lazy
|
||||
from .models import Ride, RideModel
|
||||
from .models.company import Company
|
||||
from .models.rides import Ride, RideModel
|
||||
|
||||
Manufacturer = Company
|
||||
Designer = Company
|
||||
from parks.models import Park, ParkArea
|
||||
from manufacturers.models import Manufacturer
|
||||
from designers.models import Designer
|
||||
|
||||
|
||||
class RideForm(forms.ModelForm):
|
||||
@@ -31,7 +33,7 @@ class RideForm(forms.ModelForm):
|
||||
attrs={
|
||||
"class": "w-full border-gray-300 rounded-lg form-input dark:border-gray-600 dark:bg-gray-700 dark:text-white",
|
||||
"placeholder": "Search for a manufacturer...",
|
||||
"hx-get": reverse_lazy("rides:search_manufacturers"),
|
||||
"hx-get": reverse_lazy("rides:search_companies"),
|
||||
"hx-trigger": "click, input delay:200ms",
|
||||
"hx-target": "#manufacturer-search-results",
|
||||
"name": "q",
|
||||
@@ -47,7 +49,7 @@ class RideForm(forms.ModelForm):
|
||||
attrs={
|
||||
"class": "w-full border-gray-300 rounded-lg form-input dark:border-gray-600 dark:bg-gray-700 dark:text-white",
|
||||
"placeholder": "Search for a designer...",
|
||||
"hx-get": reverse_lazy("rides:search_designers"),
|
||||
"hx-get": reverse_lazy("rides:search_companies"),
|
||||
"hx-trigger": "click, input delay:200ms",
|
||||
"hx-target": "#designer-search-results",
|
||||
"name": "q",
|
||||
|
||||
@@ -1,22 +1,123 @@
|
||||
# Generated by Django 5.1.4 on 2025-02-10 09:31
|
||||
# Generated by Django 5.1.4 on 2025-08-13 21:35
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
("manufacturers", "0001_initial"),
|
||||
("designers", "0001_initial"),
|
||||
("parks", "0001_initial"), # Changed to depend on initial parks migration
|
||||
("parks", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Company",
|
||||
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)),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("slug", models.SlugField(max_length=255, unique=True)),
|
||||
(
|
||||
"roles",
|
||||
django.contrib.postgres.fields.ArrayField(
|
||||
base_field=models.CharField(
|
||||
choices=[
|
||||
("MANUFACTURER", "Ride Manufacturer"),
|
||||
("DESIGNER", "Ride Designer"),
|
||||
],
|
||||
max_length=20,
|
||||
),
|
||||
blank=True,
|
||||
default=list,
|
||||
size=None,
|
||||
),
|
||||
),
|
||||
("description", models.TextField(blank=True)),
|
||||
("website", models.URLField(blank=True)),
|
||||
("rides_count", models.IntegerField(default=0)),
|
||||
],
|
||||
options={
|
||||
"verbose_name_plural": "Companies",
|
||||
"ordering": ["name"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="RideModel",
|
||||
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)),
|
||||
("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,
|
||||
),
|
||||
),
|
||||
(
|
||||
"manufacturer",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
limit_choices_to={"roles__contains": ["MANUFACTURER"]},
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="ride_models",
|
||||
to="rides.company",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["manufacturer", "name"],
|
||||
"unique_together": {("manufacturer", "name")},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Ride",
|
||||
fields=[
|
||||
("id", models.BigAutoField(primary_key=True, serialize=False)),
|
||||
(
|
||||
"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)),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("slug", models.SlugField(max_length=255)),
|
||||
("description", models.TextField(blank=True)),
|
||||
@@ -41,7 +142,9 @@ class Migration(migrations.Migration):
|
||||
"status",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("", "Select status"),
|
||||
("OPERATING", "Operating"),
|
||||
("CLOSED_TEMP", "Temporarily Closed"),
|
||||
("SBNO", "Standing But Not Operating"),
|
||||
("CLOSING", "Closing"),
|
||||
("CLOSED_PERM", "Permanently Closed"),
|
||||
@@ -71,33 +174,40 @@ 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(
|
||||
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,
|
||||
limit_choices_to={"roles__contains": ["DESIGNER"]},
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="rides",
|
||||
to="designers.designer",
|
||||
related_name="designed_rides",
|
||||
to="rides.company",
|
||||
),
|
||||
),
|
||||
(
|
||||
"manufacturer",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
limit_choices_to={"roles__contains": ["MANUFACTURER"]},
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="manufacturers.manufacturer",
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="manufactured_rides",
|
||||
to="rides.company",
|
||||
),
|
||||
),
|
||||
(
|
||||
@@ -118,9 +228,129 @@ class Migration(migrations.Migration):
|
||||
to="parks.parkarea",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_model",
|
||||
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",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["name"],
|
||||
"unique_together": {("park", "slug")},
|
||||
},
|
||||
),
|
||||
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",
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
# 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 = [
|
||||
("manufacturers", "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="manufacturers.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",
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,190 @@
|
||||
# Generated by Django 5.1.4 on 2025-08-14 14:50
|
||||
|
||||
import django.core.validators
|
||||
import django.db.models.deletion
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("pghistory", "0006_delete_aggregateevent"),
|
||||
("rides", "0001_initial"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="RideReview",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"rating",
|
||||
models.PositiveSmallIntegerField(
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(1),
|
||||
django.core.validators.MaxValueValidator(10),
|
||||
]
|
||||
),
|
||||
),
|
||||
("title", models.CharField(max_length=200)),
|
||||
("content", models.TextField()),
|
||||
("visit_date", models.DateField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("is_published", models.BooleanField(default=True)),
|
||||
("moderation_notes", models.TextField(blank=True)),
|
||||
("moderated_at", models.DateTimeField(blank=True, null=True)),
|
||||
(
|
||||
"moderated_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="moderated_ride_reviews",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="reviews",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="ride_reviews",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["-created_at"],
|
||||
"unique_together": {("ride", "user")},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="RideReviewEvent",
|
||||
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()),
|
||||
(
|
||||
"rating",
|
||||
models.PositiveSmallIntegerField(
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(1),
|
||||
django.core.validators.MaxValueValidator(10),
|
||||
]
|
||||
),
|
||||
),
|
||||
("title", models.CharField(max_length=200)),
|
||||
("content", models.TextField()),
|
||||
("visit_date", models.DateField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("is_published", models.BooleanField(default=True)),
|
||||
("moderation_notes", models.TextField(blank=True)),
|
||||
("moderated_at", models.DateTimeField(blank=True, null=True)),
|
||||
(
|
||||
"moderated_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
db_constraint=False,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"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.ridereview",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="ridereview",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_ridereviewevent" ("content", "created_at", "id", "is_published", "moderated_at", "moderated_by_id", "moderation_notes", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rating", "ride_id", "title", "updated_at", "user_id", "visit_date") VALUES (NEW."content", NEW."created_at", NEW."id", NEW."is_published", NEW."moderated_at", NEW."moderated_by_id", NEW."moderation_notes", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."rating", NEW."ride_id", NEW."title", NEW."updated_at", NEW."user_id", NEW."visit_date"); RETURN NULL;',
|
||||
hash="[AWS-SECRET-REMOVED]",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_33237",
|
||||
table="rides_ridereview",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="ridereview",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "rides_ridereviewevent" ("content", "created_at", "id", "is_published", "moderated_at", "moderated_by_id", "moderation_notes", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rating", "ride_id", "title", "updated_at", "user_id", "visit_date") VALUES (NEW."content", NEW."created_at", NEW."id", NEW."is_published", NEW."moderated_at", NEW."moderated_by_id", NEW."moderation_notes", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."rating", NEW."ride_id", NEW."title", NEW."updated_at", NEW."user_id", NEW."visit_date"); RETURN NULL;',
|
||||
hash="[AWS-SECRET-REMOVED]",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_90298",
|
||||
table="rides_ridereview",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -1,294 +0,0 @@
|
||||
# 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"),
|
||||
("manufacturers", "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="manufacturers.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="manufacturers.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",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
61
rides/migrations/0003_transfer_company_data.py
Normal file
61
rides/migrations/0003_transfer_company_data.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# Generated by Django 5.0.7 on 2024-07-25 14:30
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
def transfer_company_data(apps, schema_editor):
|
||||
Company = apps.get_model('rides', 'Company')
|
||||
Ride = apps.get_model('rides', 'Ride')
|
||||
RideModel = apps.get_model('rides', 'RideModel')
|
||||
|
||||
with schema_editor.connection.cursor() as cursor:
|
||||
cursor.execute("SELECT id, name, slug, description, website, founded_year, headquarters, rides_count, coasters_count FROM manufacturers_manufacturer")
|
||||
for row in cursor.fetchall():
|
||||
company, created = Company.objects.get_or_create(
|
||||
slug=row,
|
||||
defaults={
|
||||
'name': row,
|
||||
'description': row,
|
||||
'website': row,
|
||||
'founded_date': f'{row}-01-01' if row else None,
|
||||
'headquarters': row,
|
||||
'rides_count': row,
|
||||
'coasters_count': row,
|
||||
'roles': [Company.CompanyRole.MANUFACTURER]
|
||||
}
|
||||
)
|
||||
if not created and Company.CompanyRole.MANUFACTURER not in company.roles:
|
||||
company.roles.append(Company.CompanyRole.MANUFACTURER)
|
||||
company.save()
|
||||
|
||||
Ride.objects.filter(manufacturer_id=row).update(manufacturer_id=company.id)
|
||||
RideModel.objects.filter(manufacturer_id=row).update(manufacturer_id=company.id)
|
||||
|
||||
cursor.execute("SELECT id, name, slug, description, website, founded_date, headquarters FROM designers_designer")
|
||||
for row in cursor.fetchall():
|
||||
company, created = Company.objects.get_or_create(
|
||||
slug=row,
|
||||
defaults={
|
||||
'name': row,
|
||||
'description': row,
|
||||
'website': row,
|
||||
'founded_date': row,
|
||||
'headquarters': row,
|
||||
'roles': [Company.CompanyRole.DESIGNER]
|
||||
}
|
||||
)
|
||||
if not created and Company.CompanyRole.DESIGNER not in company.roles:
|
||||
company.roles.append(Company.CompanyRole.DESIGNER)
|
||||
company.save()
|
||||
|
||||
Ride.objects.filter(designer_id=row).update(designer_id=company.id)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rides', '0002_ridereview_ridereviewevent_ridereview_insert_insert_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(transfer_company_data),
|
||||
]
|
||||
@@ -0,0 +1,186 @@
|
||||
# Generated by Django 5.1.4 on 2025-08-15 01:39
|
||||
|
||||
import django.contrib.gis.db.models.fields
|
||||
import django.contrib.postgres.fields
|
||||
import django.db.models.deletion
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("pghistory", "0006_delete_aggregateevent"),
|
||||
("rides", "0003_transfer_company_data"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="CompanyEvent",
|
||||
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)),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("slug", models.SlugField(db_index=False, max_length=255)),
|
||||
(
|
||||
"roles",
|
||||
django.contrib.postgres.fields.ArrayField(
|
||||
base_field=models.CharField(
|
||||
choices=[
|
||||
("MANUFACTURER", "Ride Manufacturer"),
|
||||
("DESIGNER", "Ride Designer"),
|
||||
("OPERATOR", "Park Operator"),
|
||||
("PROPERTY_OWNER", "Property Owner"),
|
||||
],
|
||||
max_length=20,
|
||||
),
|
||||
blank=True,
|
||||
default=list,
|
||||
size=None,
|
||||
),
|
||||
),
|
||||
("description", models.TextField(blank=True)),
|
||||
("website", models.URLField(blank=True)),
|
||||
("founded_date", models.DateField(blank=True, null=True)),
|
||||
("headquarters", models.CharField(blank=True, max_length=255)),
|
||||
("rides_count", models.IntegerField(default=0)),
|
||||
("coasters_count", models.IntegerField(default=0)),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="RideLocation",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"point",
|
||||
django.contrib.gis.db.models.fields.PointField(
|
||||
blank=True, null=True, srid=4326
|
||||
),
|
||||
),
|
||||
(
|
||||
"park_area",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
help_text="Area within the park where the ride is located",
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
(
|
||||
"notes",
|
||||
models.TextField(blank=True, help_text="Specific location notes"),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Ride Location",
|
||||
"verbose_name_plural": "Ride Locations",
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="company",
|
||||
name="coasters_count",
|
||||
field=models.IntegerField(default=0),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="company",
|
||||
name="founded_date",
|
||||
field=models.DateField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="company",
|
||||
name="headquarters",
|
||||
field=models.CharField(blank=True, max_length=255),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="company",
|
||||
name="roles",
|
||||
field=django.contrib.postgres.fields.ArrayField(
|
||||
base_field=models.CharField(
|
||||
choices=[
|
||||
("MANUFACTURER", "Ride Manufacturer"),
|
||||
("DESIGNER", "Ride Designer"),
|
||||
("OPERATOR", "Park Operator"),
|
||||
("PROPERTY_OWNER", "Property Owner"),
|
||||
],
|
||||
max_length=20,
|
||||
),
|
||||
blank=True,
|
||||
default=list,
|
||||
size=None,
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="company",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_companyevent" ("coasters_count", "created_at", "description", "founded_date", "headquarters", "id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rides_count", "roles", "slug", "updated_at", "website") VALUES (NEW."coasters_count", NEW."created_at", NEW."description", NEW."founded_date", NEW."headquarters", NEW."id", NEW."name", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."rides_count", NEW."roles", NEW."slug", NEW."updated_at", NEW."website"); RETURN NULL;',
|
||||
hash="[AWS-SECRET-REMOVED]",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_e7194",
|
||||
table="rides_company",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="company",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "rides_companyevent" ("coasters_count", "created_at", "description", "founded_date", "headquarters", "id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rides_count", "roles", "slug", "updated_at", "website") VALUES (NEW."coasters_count", NEW."created_at", NEW."description", NEW."founded_date", NEW."headquarters", NEW."id", NEW."name", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."rides_count", NEW."roles", NEW."slug", NEW."updated_at", NEW."website"); RETURN NULL;',
|
||||
hash="[AWS-SECRET-REMOVED]",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_456a8",
|
||||
table="rides_company",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="companyevent",
|
||||
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="companyevent",
|
||||
name="pgh_obj",
|
||||
field=models.ForeignKey(
|
||||
db_constraint=False,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="events",
|
||||
to="rides.company",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="ridelocation",
|
||||
name="ride",
|
||||
field=models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="location",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -1,120 +0,0 @@
|
||||
# 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",
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -1,35 +0,0 @@
|
||||
# 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",
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,61 @@
|
||||
# Generated by Django 5.1.4 on 2025-08-15 01:41
|
||||
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("rides", "0004_companyevent_ridelocation_company_coasters_count_and_more"),
|
||||
("parks", "0004_remove_company_headquarters_companyheadquarters"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="company",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="company",
|
||||
name="update_update",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="company",
|
||||
name="headquarters",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="companyevent",
|
||||
name="headquarters",
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="company",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_companyevent" ("coasters_count", "created_at", "description", "founded_date", "id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rides_count", "roles", "slug", "updated_at", "website") VALUES (NEW."coasters_count", NEW."created_at", NEW."description", NEW."founded_date", NEW."id", NEW."name", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."rides_count", NEW."roles", NEW."slug", NEW."updated_at", NEW."website"); RETURN NULL;',
|
||||
hash="[AWS-SECRET-REMOVED]",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_e7194",
|
||||
table="rides_company",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="company",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "rides_companyevent" ("coasters_count", "created_at", "description", "founded_date", "id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rides_count", "roles", "slug", "updated_at", "website") VALUES (NEW."coasters_count", NEW."created_at", NEW."description", NEW."founded_date", NEW."id", NEW."name", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."rides_count", NEW."roles", NEW."slug", NEW."updated_at", NEW."website"); RETURN NULL;',
|
||||
hash="[AWS-SECRET-REMOVED]",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_456a8",
|
||||
table="rides_company",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -1,76 +0,0 @@
|
||||
# Generated by Django 5.1.4 on 2025-02-21 17:55
|
||||
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("parks", "0003_alter_park_id_alter_parkarea_id_and_more"),
|
||||
("rides", "0005_fix_event_context_fields"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="rideevent",
|
||||
options={"managed": False},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name="ridemodelevent",
|
||||
options={"managed": False},
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="ride",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="ride",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="ridemodel",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="ridemodel",
|
||||
name="update_update",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ride",
|
||||
name="id",
|
||||
field=models.BigAutoField(
|
||||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ride",
|
||||
name="status",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("", "Select status"),
|
||||
("OPERATING", "Operating"),
|
||||
("CLOSED_TEMP", "Temporarily Closed"),
|
||||
("SBNO", "Standing But Not Operating"),
|
||||
("CLOSING", "Closing"),
|
||||
("CLOSED_PERM", "Permanently Closed"),
|
||||
("UNDER_CONSTRUCTION", "Under Construction"),
|
||||
("DEMOLISHED", "Demolished"),
|
||||
("RELOCATED", "Relocated"),
|
||||
],
|
||||
default="OPERATING",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ridemodel",
|
||||
name="id",
|
||||
field=models.BigAutoField(
|
||||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name="ride",
|
||||
unique_together={("park", "slug")},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
# Generated by Django 5.1.4 on 2025-08-15 14:16
|
||||
|
||||
import django.contrib.gis.db.models.fields
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("rides", "0005_remove_company_insert_insert_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="ridelocation",
|
||||
options={
|
||||
"ordering": ["ride__name"],
|
||||
"verbose_name": "Ride Location",
|
||||
"verbose_name_plural": "Ride Locations",
|
||||
},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="ridelocation",
|
||||
name="notes",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="ridelocation",
|
||||
name="accessibility_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Information about accessible entrances, wheelchair access, etc.",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="ridelocation",
|
||||
name="created_at",
|
||||
field=models.DateTimeField(
|
||||
auto_now_add=True, default=django.utils.timezone.now
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="ridelocation",
|
||||
name="entrance_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Directions to ride entrance, queue location, or navigation tips",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="ridelocation",
|
||||
name="updated_at",
|
||||
field=models.DateTimeField(auto_now=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ridelocation",
|
||||
name="park_area",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
db_index=True,
|
||||
help_text="Themed area or land within the park (e.g., 'Frontierland', 'Tomorrowland')",
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ridelocation",
|
||||
name="point",
|
||||
field=django.contrib.gis.db.models.fields.PointField(
|
||||
blank=True,
|
||||
help_text="Geographic coordinates for ride location (longitude, latitude)",
|
||||
null=True,
|
||||
srid=4326,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ridelocation",
|
||||
name="ride",
|
||||
field=models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="ride_location",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="ridelocation",
|
||||
index=models.Index(
|
||||
fields=["park_area"], name="rides_ridel_park_ar_26c90c_idx"
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -1,45 +0,0 @@
|
||||
# Generated by Django 5.1.4 on 2025-07-04 15:26
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("manufacturers", "0001_initial"),
|
||||
("rides", "0006_alter_rideevent_options_alter_ridemodelevent_options_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="ride",
|
||||
name="manufacturer",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="rides",
|
||||
to="manufacturers.manufacturer",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ridemodel",
|
||||
name="manufacturer",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="ride_models",
|
||||
to="manufacturers.manufacturer",
|
||||
),
|
||||
),
|
||||
migrations.AlterModelTable(
|
||||
name="rideevent",
|
||||
table="rides_rideevent",
|
||||
),
|
||||
migrations.AlterModelTable(
|
||||
name="ridemodelevent",
|
||||
table="rides_ridemodelevent",
|
||||
),
|
||||
]
|
||||
66
rides/migrations/0007_update_ridelocation_fields.py
Normal file
66
rides/migrations/0007_update_ridelocation_fields.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# Generated by Django 5.1.4 on 2025-08-15 14:18
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.contrib.gis.db import models as gis_models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("rides", "0006_alter_ridelocation_options_remove_ridelocation_notes_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
# Add new fields according to our enhanced model
|
||||
migrations.AddField(
|
||||
model_name='ridelocation',
|
||||
name='entrance_notes',
|
||||
field=models.TextField(blank=True, help_text='Directions to ride entrance, queue location, or navigation tips'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='ridelocation',
|
||||
name='accessibility_notes',
|
||||
field=models.TextField(blank=True, help_text='Information about accessible entrances, wheelchair access, etc.'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='ridelocation',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='ridelocation',
|
||||
name='updated_at',
|
||||
field=models.DateTimeField(auto_now=True),
|
||||
),
|
||||
|
||||
# Update existing fields
|
||||
migrations.AlterField(
|
||||
model_name='ridelocation',
|
||||
name='park_area',
|
||||
field=models.CharField(blank=True, db_index=True, help_text="Themed area or land within the park (e.g., 'Frontierland', 'Tomorrowland')", max_length=100),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='ridelocation',
|
||||
name='point',
|
||||
field=gis_models.PointField(blank=True, help_text='Geographic coordinates for ride location (longitude, latitude)', null=True, srid=4326),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='ridelocation',
|
||||
name='ride',
|
||||
field=models.OneToOneField(on_delete=models.CASCADE, related_name='ride_location', to='rides.ride'),
|
||||
),
|
||||
|
||||
# Update Meta options
|
||||
migrations.AlterModelOptions(
|
||||
name='ridelocation',
|
||||
options={'ordering': ['ride__name'], 'verbose_name': 'Ride Location', 'verbose_name_plural': 'Ride Locations'},
|
||||
),
|
||||
|
||||
# Add index for park_area if it doesn't exist
|
||||
migrations.AddIndex(
|
||||
model_name='ridelocation',
|
||||
index=models.Index(fields=['park_area'], name='rides_ridelocation_park_area_idx'),
|
||||
),
|
||||
]
|
||||
@@ -1,9 +1,10 @@
|
||||
from django.db import models
|
||||
from django.utils.text import slugify
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from history_tracking.models import TrackedModel, DiffMixin
|
||||
from manufacturers.models import Manufacturer
|
||||
from core.history import TrackedModel, DiffMixin
|
||||
from .events import get_ride_display_changes, get_ride_model_display_changes
|
||||
import pghistory
|
||||
from .company import Company
|
||||
|
||||
# Shared choices that will be used by multiple models
|
||||
CATEGORY_CHOICES = [
|
||||
@@ -45,8 +46,6 @@ class RideEvent(models.Model, DiffMixin):
|
||||
# Foreign keys as IDs
|
||||
park_id = models.BigIntegerField()
|
||||
park_area_id = models.BigIntegerField(null=True)
|
||||
manufacturer_id = models.BigIntegerField(null=True)
|
||||
designer_id = models.BigIntegerField(null=True)
|
||||
ride_model_id = models.BigIntegerField(null=True)
|
||||
|
||||
# Context fields
|
||||
@@ -110,11 +109,12 @@ class RideModel(TrackedModel):
|
||||
"""
|
||||
name = models.CharField(max_length=255)
|
||||
manufacturer = models.ForeignKey(
|
||||
Manufacturer,
|
||||
Company,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='ride_models',
|
||||
null=True,
|
||||
blank=True
|
||||
blank=True,
|
||||
limit_choices_to={'roles__contains': [Company.CompanyRole.MANUFACTURER]}
|
||||
)
|
||||
description = models.TextField(blank=True)
|
||||
category = models.CharField(
|
||||
@@ -172,18 +172,20 @@ class Ride(TrackedModel):
|
||||
blank=True
|
||||
)
|
||||
manufacturer = models.ForeignKey(
|
||||
Manufacturer,
|
||||
Company,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='rides'
|
||||
related_name='manufactured_rides',
|
||||
limit_choices_to={'roles__contains': [Company.CompanyRole.MANUFACTURER]}
|
||||
)
|
||||
designer = models.ForeignKey(
|
||||
'designers.Designer',
|
||||
Company,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='rides',
|
||||
related_name='designed_rides',
|
||||
null=True,
|
||||
blank=True
|
||||
blank=True,
|
||||
limit_choices_to={'roles__contains': [Company.CompanyRole.DESIGNER]}
|
||||
)
|
||||
ride_model = models.ForeignKey(
|
||||
'RideModel',
|
||||
@@ -219,7 +221,6 @@ class Ride(TrackedModel):
|
||||
blank=True
|
||||
)
|
||||
photos = GenericRelation('media.Photo')
|
||||
reviews = GenericRelation('reviews.Review')
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
|
||||
3
rides/models/__init__.py
Normal file
3
rides/models/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .rides import *
|
||||
from .reviews import *
|
||||
from .location import *
|
||||
77
rides/models/company.py
Normal file
77
rides/models/company.py
Normal file
@@ -0,0 +1,77 @@
|
||||
import pghistory
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.text import slugify
|
||||
|
||||
from core.history import HistoricalSlug
|
||||
from core.models import TrackedModel
|
||||
|
||||
|
||||
@pghistory.track()
|
||||
class Company(TrackedModel):
|
||||
class CompanyRole(models.TextChoices):
|
||||
MANUFACTURER = 'MANUFACTURER', 'Ride Manufacturer'
|
||||
DESIGNER = 'DESIGNER', 'Ride Designer'
|
||||
OPERATOR = 'OPERATOR', 'Park Operator'
|
||||
PROPERTY_OWNER = 'PROPERTY_OWNER', 'Property Owner'
|
||||
|
||||
name = models.CharField(max_length=255)
|
||||
slug = models.SlugField(max_length=255, unique=True)
|
||||
roles = ArrayField(
|
||||
models.CharField(max_length=20, choices=CompanyRole.choices),
|
||||
default=list,
|
||||
blank=True
|
||||
)
|
||||
description = models.TextField(blank=True)
|
||||
website = models.URLField(blank=True)
|
||||
|
||||
# General company info
|
||||
founded_date = models.DateField(null=True, blank=True)
|
||||
|
||||
# Manufacturer-specific fields
|
||||
rides_count = models.IntegerField(default=0)
|
||||
coasters_count = models.IntegerField(default=0)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
self.slug = slugify(self.name)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def get_absolute_url(self):
|
||||
# This will need to be updated to handle different roles
|
||||
return reverse('companies:detail', kwargs={'slug': self.slug})
|
||||
return '#'
|
||||
|
||||
@classmethod
|
||||
def get_by_slug(cls, slug):
|
||||
"""Get company by current or historical slug"""
|
||||
try:
|
||||
return cls.objects.get(slug=slug), False
|
||||
except cls.DoesNotExist:
|
||||
# Check pghistory first
|
||||
history_model = cls.get_history_model()
|
||||
history_entry = (
|
||||
history_model.objects.filter(slug=slug)
|
||||
.order_by('-pgh_created_at')
|
||||
.first()
|
||||
)
|
||||
if history_entry:
|
||||
return cls.objects.get(id=history_entry.pgh_obj_id), True
|
||||
|
||||
# Check manual slug history as fallback
|
||||
try:
|
||||
historical = HistoricalSlug.objects.get(
|
||||
content_type__model='company',
|
||||
slug=slug
|
||||
)
|
||||
return cls.objects.get(pk=historical.object_id), True
|
||||
except (HistoricalSlug.DoesNotExist, cls.DoesNotExist):
|
||||
raise cls.DoesNotExist("No company found with this slug")
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
verbose_name_plural = 'Companies'
|
||||
125
rides/models/location.py
Normal file
125
rides/models/location.py
Normal file
@@ -0,0 +1,125 @@
|
||||
from django.contrib.gis.db import models as gis_models
|
||||
from django.db import models
|
||||
from django.contrib.gis.geos import Point
|
||||
|
||||
|
||||
class RideLocation(models.Model):
|
||||
"""
|
||||
Lightweight location tracking for individual rides within parks.
|
||||
Optional coordinates with focus on practical navigation information.
|
||||
"""
|
||||
# Relationships
|
||||
ride = models.OneToOneField(
|
||||
'rides.Ride',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='ride_location'
|
||||
)
|
||||
|
||||
# Optional Spatial Data - keep it simple with single point
|
||||
point = gis_models.PointField(
|
||||
srid=4326,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Geographic coordinates for ride location (longitude, latitude)"
|
||||
)
|
||||
|
||||
# Park Area Information
|
||||
park_area = models.CharField(
|
||||
max_length=100,
|
||||
blank=True,
|
||||
db_index=True,
|
||||
help_text="Themed area or land within the park (e.g., 'Frontierland', 'Tomorrowland')"
|
||||
)
|
||||
|
||||
# General notes field to match database schema
|
||||
notes = models.TextField(
|
||||
blank=True,
|
||||
help_text="General location notes"
|
||||
)
|
||||
|
||||
# Navigation and Entrance Information
|
||||
entrance_notes = models.TextField(
|
||||
blank=True,
|
||||
help_text="Directions to ride entrance, queue location, or navigation tips"
|
||||
)
|
||||
|
||||
# Accessibility Information
|
||||
accessibility_notes = models.TextField(
|
||||
blank=True,
|
||||
help_text="Information about accessible entrances, wheelchair access, etc."
|
||||
)
|
||||
|
||||
# Metadata
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
@property
|
||||
def latitude(self):
|
||||
"""Return latitude from point field for backward compatibility."""
|
||||
if self.point:
|
||||
return self.point.y
|
||||
return None
|
||||
|
||||
@property
|
||||
def longitude(self):
|
||||
"""Return longitude from point field for backward compatibility."""
|
||||
if self.point:
|
||||
return self.point.x
|
||||
return None
|
||||
|
||||
@property
|
||||
def coordinates(self):
|
||||
"""Return (latitude, longitude) tuple."""
|
||||
if self.point:
|
||||
return (self.latitude, self.longitude)
|
||||
return (None, None)
|
||||
|
||||
@property
|
||||
def has_coordinates(self):
|
||||
"""Check if coordinates are set."""
|
||||
return self.point is not None
|
||||
|
||||
def set_coordinates(self, latitude, longitude):
|
||||
"""
|
||||
Set the location's point from latitude and longitude coordinates.
|
||||
Validates coordinate ranges.
|
||||
"""
|
||||
if latitude is None or longitude is None:
|
||||
self.point = None
|
||||
return
|
||||
|
||||
if not -90 <= latitude <= 90:
|
||||
raise ValueError("Latitude must be between -90 and 90.")
|
||||
if not -180 <= longitude <= 180:
|
||||
raise ValueError("Longitude must be between -180 and 180.")
|
||||
|
||||
self.point = Point(longitude, latitude, srid=4326)
|
||||
|
||||
def distance_to_park_location(self):
|
||||
"""
|
||||
Calculate distance to parent park's location if both have coordinates.
|
||||
Returns distance in kilometers.
|
||||
"""
|
||||
if not self.point:
|
||||
return None
|
||||
|
||||
park_location = getattr(self.ride.park, 'location', None)
|
||||
if not park_location or not park_location.point:
|
||||
return None
|
||||
|
||||
# Use geodetic distance calculation which returns meters, convert to km
|
||||
distance_m = self.point.distance(park_location.point)
|
||||
return distance_m / 1000.0
|
||||
|
||||
def __str__(self):
|
||||
area_str = f" in {self.park_area}" if self.park_area else ""
|
||||
return f"Location for {self.ride.name}{area_str}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Ride Location"
|
||||
verbose_name_plural = "Ride Locations"
|
||||
ordering = ['ride__name']
|
||||
indexes = [
|
||||
models.Index(fields=['park_area']),
|
||||
# Spatial index will be created automatically for PostGIS PointField
|
||||
]
|
||||
49
rides/models/reviews.py
Normal file
49
rides/models/reviews.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from django.db import models
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||
from core.history import TrackedModel
|
||||
import pghistory
|
||||
|
||||
@pghistory.track()
|
||||
class RideReview(TrackedModel):
|
||||
"""
|
||||
A review of a ride.
|
||||
"""
|
||||
ride = models.ForeignKey(
|
||||
'rides.Ride',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='reviews'
|
||||
)
|
||||
user = models.ForeignKey(
|
||||
'accounts.User',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='ride_reviews'
|
||||
)
|
||||
rating = models.PositiveSmallIntegerField(
|
||||
validators=[MinValueValidator(1), MaxValueValidator(10)]
|
||||
)
|
||||
title = models.CharField(max_length=200)
|
||||
content = models.TextField()
|
||||
visit_date = models.DateField()
|
||||
|
||||
# Metadata
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
# Moderation
|
||||
is_published = models.BooleanField(default=True)
|
||||
moderation_notes = models.TextField(blank=True)
|
||||
moderated_by = models.ForeignKey(
|
||||
'accounts.User',
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='moderated_ride_reviews'
|
||||
)
|
||||
moderated_at = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-created_at']
|
||||
unique_together = ['ride', 'user']
|
||||
|
||||
def __str__(self):
|
||||
return f"Review of {self.ride.name} by {self.user.username}"
|
||||
239
rides/models/rides.py
Normal file
239
rides/models/rides.py
Normal file
@@ -0,0 +1,239 @@
|
||||
from django.db import models
|
||||
from django.utils.text import slugify
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from core.models import TrackedModel
|
||||
from .company import Company
|
||||
|
||||
# Shared choices that will be used by multiple models
|
||||
CATEGORY_CHOICES = [
|
||||
('', 'Select ride type'),
|
||||
('RC', 'Roller Coaster'),
|
||||
('DR', 'Dark Ride'),
|
||||
('FR', 'Flat Ride'),
|
||||
('WR', 'Water Ride'),
|
||||
('TR', 'Transport'),
|
||||
('OT', 'Other'),
|
||||
]
|
||||
|
||||
class RideModel(TrackedModel):
|
||||
"""
|
||||
Represents a specific model/type of ride that can be manufactured by different companies.
|
||||
For example: B&M Dive Coaster, Vekoma Boomerang, etc.
|
||||
"""
|
||||
name = models.CharField(max_length=255)
|
||||
manufacturer = models.ForeignKey(
|
||||
Company,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='ride_models',
|
||||
null=True,
|
||||
blank=True,
|
||||
limit_choices_to={'roles__contains': ['MANUFACTURER']},
|
||||
)
|
||||
description = models.TextField(blank=True)
|
||||
category = models.CharField(
|
||||
max_length=2,
|
||||
choices=CATEGORY_CHOICES,
|
||||
default='',
|
||||
blank=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['manufacturer', 'name']
|
||||
unique_together = ['manufacturer', 'name']
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.name if not self.manufacturer else f"{self.manufacturer.name} {self.name}"
|
||||
|
||||
class Ride(TrackedModel):
|
||||
"""Model for individual ride installations at parks"""
|
||||
STATUS_CHOICES = [
|
||||
('', 'Select status'),
|
||||
('OPERATING', 'Operating'),
|
||||
('CLOSED_TEMP', 'Temporarily Closed'),
|
||||
('SBNO', 'Standing But Not Operating'),
|
||||
('CLOSING', 'Closing'),
|
||||
('CLOSED_PERM', 'Permanently Closed'),
|
||||
('UNDER_CONSTRUCTION', 'Under Construction'),
|
||||
('DEMOLISHED', 'Demolished'),
|
||||
('RELOCATED', 'Relocated'),
|
||||
]
|
||||
|
||||
POST_CLOSING_STATUS_CHOICES = [
|
||||
('SBNO', 'Standing But Not Operating'),
|
||||
('CLOSED_PERM', 'Permanently Closed'),
|
||||
]
|
||||
|
||||
name = models.CharField(max_length=255)
|
||||
slug = models.SlugField(max_length=255)
|
||||
description = models.TextField(blank=True)
|
||||
park = models.ForeignKey(
|
||||
'parks.Park',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='rides'
|
||||
)
|
||||
park_area = models.ForeignKey(
|
||||
'parks.ParkArea',
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='rides',
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
category = models.CharField(
|
||||
max_length=2,
|
||||
choices=CATEGORY_CHOICES,
|
||||
default='',
|
||||
blank=True
|
||||
)
|
||||
manufacturer = models.ForeignKey(
|
||||
Company,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='manufactured_rides',
|
||||
limit_choices_to={'roles__contains': ['MANUFACTURER']},
|
||||
)
|
||||
designer = models.ForeignKey(
|
||||
Company,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='designed_rides',
|
||||
null=True,
|
||||
blank=True,
|
||||
limit_choices_to={'roles__contains': ['DESIGNER']},
|
||||
)
|
||||
ride_model = models.ForeignKey(
|
||||
'RideModel',
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='rides',
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="The specific model/type of this ride"
|
||||
)
|
||||
status = models.CharField(
|
||||
max_length=20,
|
||||
choices=STATUS_CHOICES,
|
||||
default='OPERATING'
|
||||
)
|
||||
post_closing_status = models.CharField(
|
||||
max_length=20,
|
||||
choices=POST_CLOSING_STATUS_CHOICES,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Status to change to after closing date"
|
||||
)
|
||||
opening_date = models.DateField(null=True, blank=True)
|
||||
closing_date = models.DateField(null=True, blank=True)
|
||||
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)
|
||||
capacity_per_hour = models.PositiveIntegerField(null=True, blank=True)
|
||||
ride_duration_seconds = models.PositiveIntegerField(null=True, blank=True)
|
||||
average_rating = models.DecimalField(
|
||||
max_digits=3,
|
||||
decimal_places=2,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
photos = GenericRelation('media.Photo')
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
unique_together = ['park', 'slug']
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.name} at {self.park.name}"
|
||||
|
||||
def save(self, *args, **kwargs) -> None:
|
||||
if not self.slug:
|
||||
self.slug = slugify(self.name)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
class RollerCoasterStats(models.Model):
|
||||
"""Model for tracking roller coaster specific statistics"""
|
||||
TRACK_MATERIAL_CHOICES = [
|
||||
('STEEL', 'Steel'),
|
||||
('WOOD', 'Wood'),
|
||||
('HYBRID', 'Hybrid'),
|
||||
]
|
||||
|
||||
COASTER_TYPE_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'),
|
||||
]
|
||||
|
||||
LAUNCH_CHOICES = [
|
||||
('CHAIN', 'Chain Lift'),
|
||||
('LSM', 'LSM Launch'),
|
||||
('HYDRAULIC', 'Hydraulic Launch'),
|
||||
('GRAVITY', 'Gravity'),
|
||||
('OTHER', 'Other'),
|
||||
]
|
||||
|
||||
ride = models.OneToOneField(
|
||||
Ride,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='coaster_stats'
|
||||
)
|
||||
height_ft = models.DecimalField(
|
||||
max_digits=6,
|
||||
decimal_places=2,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
length_ft = models.DecimalField(
|
||||
max_digits=7,
|
||||
decimal_places=2,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
speed_mph = models.DecimalField(
|
||||
max_digits=5,
|
||||
decimal_places=2,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
inversions = models.PositiveIntegerField(default=0)
|
||||
ride_time_seconds = models.PositiveIntegerField(null=True, blank=True)
|
||||
track_type = models.CharField(max_length=255, blank=True)
|
||||
track_material = models.CharField(
|
||||
max_length=20,
|
||||
choices=TRACK_MATERIAL_CHOICES,
|
||||
default='STEEL',
|
||||
blank=True
|
||||
)
|
||||
roller_coaster_type = models.CharField(
|
||||
max_length=20,
|
||||
choices=COASTER_TYPE_CHOICES,
|
||||
default='SITDOWN',
|
||||
blank=True
|
||||
)
|
||||
max_drop_height_ft = models.DecimalField(
|
||||
max_digits=6,
|
||||
decimal_places=2,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
launch_type = models.CharField(
|
||||
max_length=20,
|
||||
choices=LAUNCH_CHOICES,
|
||||
default='CHAIN'
|
||||
)
|
||||
train_style = models.CharField(max_length=255, blank=True)
|
||||
trains_count = models.PositiveIntegerField(null=True, blank=True)
|
||||
cars_per_train = models.PositiveIntegerField(null=True, blank=True)
|
||||
seats_per_car = models.PositiveIntegerField(null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Roller Coaster Statistics'
|
||||
verbose_name_plural = 'Roller Coaster Statistics'
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Stats for {self.ride.name}"
|
||||
@@ -19,18 +19,13 @@ urlpatterns = [
|
||||
views.RideUpdateView.as_view(),
|
||||
name="ride_update"
|
||||
),
|
||||
path(
|
||||
"search/companies/",
|
||||
views.search_companies,
|
||||
name="search_companies"
|
||||
),
|
||||
|
||||
# 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,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{% for company in companies %}
|
||||
<div>{{ company.name }}</div>
|
||||
{% endfor %}
|
||||
@@ -46,21 +46,16 @@ urlpatterns = [
|
||||
),
|
||||
|
||||
# Search endpoints (must come before slug patterns)
|
||||
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"
|
||||
),
|
||||
path(
|
||||
"search/companies/",
|
||||
views.search_companies,
|
||||
name="search_companies"
|
||||
),
|
||||
|
||||
# HTMX endpoints (must come before slug patterns)
|
||||
path(
|
||||
|
||||
@@ -9,16 +9,14 @@ from django.contrib import messages
|
||||
from django.http import HttpRequest, HttpResponse, Http404
|
||||
from django.db.models import Count
|
||||
from .models import (
|
||||
Ride, RollerCoasterStats, RideModel, RideEvent,
|
||||
CATEGORY_CHOICES
|
||||
Ride, RollerCoasterStats, RideModel,
|
||||
CATEGORY_CHOICES, Company
|
||||
)
|
||||
from .forms import RideForm
|
||||
from parks.models import Park
|
||||
from core.views import SlugRedirectMixin
|
||||
from moderation.mixins import EditSubmissionMixin, PhotoSubmissionMixin, HistoryMixin
|
||||
from moderation.models import EditSubmission
|
||||
from manufacturers.models import Manufacturer
|
||||
from designers.models import Designer
|
||||
|
||||
|
||||
class ParkContextRequired:
|
||||
@@ -64,11 +62,6 @@ class RideDetailView(HistoryMixin, DetailView):
|
||||
context['park_slug'] = self.kwargs['park_slug']
|
||||
context['park'] = self.object.park
|
||||
|
||||
# Add history records
|
||||
context['history'] = RideEvent.objects.filter(
|
||||
pgh_obj_id=self.object.id
|
||||
).order_by('-pgh_created_at')
|
||||
|
||||
return context
|
||||
|
||||
|
||||
@@ -107,9 +100,9 @@ class RideCreateView(LoginRequiredMixin, ParkContextRequired, CreateView):
|
||||
if manufacturer_name and not form.cleaned_data.get('manufacturer'):
|
||||
EditSubmission.objects.create(
|
||||
user=self.request.user,
|
||||
content_type=ContentType.objects.get_for_model(Manufacturer),
|
||||
content_type=ContentType.objects.get_for_model(Company),
|
||||
submission_type="CREATE",
|
||||
changes={"name": manufacturer_name},
|
||||
changes={"name": manufacturer_name, "roles": ["MANUFACTURER"]},
|
||||
)
|
||||
|
||||
# Check for new designer
|
||||
@@ -117,9 +110,9 @@ class RideCreateView(LoginRequiredMixin, ParkContextRequired, CreateView):
|
||||
if designer_name and not form.cleaned_data.get('designer'):
|
||||
EditSubmission.objects.create(
|
||||
user=self.request.user,
|
||||
content_type=ContentType.objects.get_for_model(Designer),
|
||||
content_type=ContentType.objects.get_for_model(Company),
|
||||
submission_type="CREATE",
|
||||
changes={"name": designer_name},
|
||||
changes={"name": designer_name, "roles": ["DESIGNER"]},
|
||||
)
|
||||
|
||||
# Check for new ride model
|
||||
@@ -179,9 +172,9 @@ class RideUpdateView(LoginRequiredMixin, ParkContextRequired, EditSubmissionMixi
|
||||
if manufacturer_name and not form.cleaned_data.get('manufacturer'):
|
||||
EditSubmission.objects.create(
|
||||
user=self.request.user,
|
||||
content_type=ContentType.objects.get_for_model(Manufacturer),
|
||||
content_type=ContentType.objects.get_for_model(Company),
|
||||
submission_type="CREATE",
|
||||
changes={"name": manufacturer_name}
|
||||
changes={"name": manufacturer_name, "roles": ["MANUFACTURER"]}
|
||||
)
|
||||
|
||||
# Check for new designer
|
||||
@@ -189,9 +182,9 @@ class RideUpdateView(LoginRequiredMixin, ParkContextRequired, EditSubmissionMixi
|
||||
if designer_name and not form.cleaned_data.get('designer'):
|
||||
EditSubmission.objects.create(
|
||||
user=self.request.user,
|
||||
content_type=ContentType.objects.get_for_model(Designer),
|
||||
content_type=ContentType.objects.get_for_model(Company),
|
||||
submission_type="CREATE",
|
||||
changes={"name": designer_name}
|
||||
changes={"name": designer_name, "roles": ["DESIGNER"]}
|
||||
)
|
||||
|
||||
# Check for new ride model
|
||||
@@ -314,40 +307,26 @@ class SingleCategoryListView(ListView):
|
||||
ParkSingleCategoryListView = SingleCategoryListView
|
||||
|
||||
|
||||
def search_manufacturers(request: HttpRequest) -> HttpResponse:
|
||||
"""Search manufacturers and return results for HTMX"""
|
||||
query = request.GET.get("q", "").strip()
|
||||
|
||||
# Show all manufacturers on click, filter on input
|
||||
manufacturers = Manufacturer.objects.all().order_by("name")
|
||||
|
||||
def search_companies(request: HttpRequest) -> HttpResponse:
|
||||
"""Search companies and return results for HTMX"""
|
||||
query = request.GET.get("q", "").strip()
|
||||
role = request.GET.get("role", "").upper()
|
||||
|
||||
companies = Company.objects.all().order_by("name")
|
||||
if role:
|
||||
companies = companies.filter(roles__contains=[role])
|
||||
if query:
|
||||
manufacturers = manufacturers.filter(name__icontains=query)
|
||||
manufacturers = manufacturers[:10]
|
||||
companies = companies.filter(name__icontains=query)
|
||||
companies = companies[:10]
|
||||
|
||||
return render(
|
||||
request,
|
||||
"rides/partials/manufacturer_search_results.html",
|
||||
{"manufacturers": manufacturers, "search_term": query},
|
||||
"rides/partials/company_search_results.html",
|
||||
{"companies": companies, "search_term": query},
|
||||
)
|
||||
|
||||
|
||||
def search_designers(request: HttpRequest) -> HttpResponse:
|
||||
"""Search designers and return results for HTMX"""
|
||||
query = request.GET.get("q", "").strip()
|
||||
|
||||
# Show all designers on click, filter on input
|
||||
designers = Designer.objects.all().order_by("name")
|
||||
if query:
|
||||
designers = designers.filter(name__icontains=query)
|
||||
designers = designers[:10]
|
||||
|
||||
return render(
|
||||
request,
|
||||
"rides/partials/designer_search_results.html",
|
||||
{"designers": designers, "search_term": query},
|
||||
)
|
||||
|
||||
|
||||
def search_ride_models(request: HttpRequest) -> HttpResponse:
|
||||
"""Search ride models and return results for HTMX"""
|
||||
query = request.GET.get("q", "").strip()
|
||||
|
||||
Reference in New Issue
Block a user