Files
thrillwiki_django_no_react/rides/models.py

240 lines
6.9 KiB
Python

from django.db import models
from django.utils.text import slugify
from django.contrib.contenttypes.fields import GenericRelation
from history_tracking.models import HistoricalModel
# 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(HistoricalModel):
"""
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(
'companies.Manufacturer',
on_delete=models.SET_NULL, # Changed to SET_NULL since it's optional
related_name='ride_models',
null=True, # Made optional
blank=True # Made optional
)
description = models.TextField(blank=True)
category = models.CharField(
max_length=2,
choices=CATEGORY_CHOICES,
default='',
blank=True
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=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(HistoricalModel):
STATUS_CHOICES = [
('OPERATING', 'Operating'),
('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(
'companies.Manufacturer',
on_delete=models.CASCADE,
null=True,
blank=True
)
designer = models.ForeignKey(
'companies.Designer',
on_delete=models.SET_NULL,
related_name='rides',
null=True,
blank=True
)
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
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
photos = GenericRelation('media.Photo')
reviews = GenericRelation('reviews.Review')
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):
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}"