mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 07:51:09 -05:00
first commit
This commit is contained in:
0
rides/__init__.py
Normal file
0
rides/__init__.py
Normal file
BIN
rides/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
rides/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
rides/__pycache__/admin.cpython-311.pyc
Normal file
BIN
rides/__pycache__/admin.cpython-311.pyc
Normal file
Binary file not shown.
BIN
rides/__pycache__/apps.cpython-311.pyc
Normal file
BIN
rides/__pycache__/apps.cpython-311.pyc
Normal file
Binary file not shown.
BIN
rides/__pycache__/models.cpython-311.pyc
Normal file
BIN
rides/__pycache__/models.cpython-311.pyc
Normal file
Binary file not shown.
BIN
rides/__pycache__/signals.cpython-311.pyc
Normal file
BIN
rides/__pycache__/signals.cpython-311.pyc
Normal file
Binary file not shown.
BIN
rides/__pycache__/urls.cpython-311.pyc
Normal file
BIN
rides/__pycache__/urls.cpython-311.pyc
Normal file
Binary file not shown.
BIN
rides/__pycache__/views.cpython-311.pyc
Normal file
BIN
rides/__pycache__/views.cpython-311.pyc
Normal file
Binary file not shown.
169
rides/admin.py
Normal file
169
rides/admin.py
Normal file
@@ -0,0 +1,169 @@
|
||||
from django.contrib import admin
|
||||
from django.utils.html import format_html
|
||||
from django.db.models import Avg
|
||||
from simple_history.admin import SimpleHistoryAdmin
|
||||
from .models import Ride, RollerCoasterStats
|
||||
|
||||
class RollerCoasterStatsInline(admin.StackedInline):
|
||||
model = RollerCoasterStats
|
||||
can_delete = False
|
||||
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')
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
@admin.register(Ride)
|
||||
class RideAdmin(SimpleHistoryAdmin):
|
||||
list_display = ('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 = ('created_at', 'updated_at')
|
||||
history_list_display = ['status', 'manufacturer']
|
||||
actions = ['mark_as_operating', 'mark_as_closed', 'mark_as_under_maintenance', 'mark_as_removed']
|
||||
|
||||
fieldsets = (
|
||||
('Basic Information', {
|
||||
'fields': (
|
||||
'name',
|
||||
'slug',
|
||||
'description',
|
||||
'park',
|
||||
'park_area'
|
||||
)
|
||||
}),
|
||||
('Ride Details', {
|
||||
'fields': (
|
||||
'category',
|
||||
'manufacturer',
|
||||
'model_name',
|
||||
'status'
|
||||
)
|
||||
}),
|
||||
('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'
|
||||
)
|
||||
}),
|
||||
('Metadata', {
|
||||
'fields': ('created_at', 'updated_at'),
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
)
|
||||
|
||||
def get_status(self, obj):
|
||||
status_colors = {
|
||||
'operating': 'green',
|
||||
'closed': 'red',
|
||||
'under_maintenance': 'orange',
|
||||
'under_construction': 'blue',
|
||||
'removed': 'grey'
|
||||
}
|
||||
return format_html(
|
||||
'<span style="color: {};">{}</span>',
|
||||
status_colors.get(obj.status, 'black'),
|
||||
obj.get_status_display()
|
||||
)
|
||||
get_status.short_description = 'Status'
|
||||
|
||||
def get_avg_rating(self, obj):
|
||||
avg = obj.reviews.filter(status='approved').aggregate(avg_rating=Avg('rating'))['avg_rating']
|
||||
if avg:
|
||||
return format_html(
|
||||
'<span style="color: {};">★ {:.1f}</span>',
|
||||
'gold',
|
||||
avg
|
||||
)
|
||||
return '-'
|
||||
get_avg_rating.short_description = 'Rating'
|
||||
|
||||
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')
|
||||
mark_as_closed.short_description = "Mark selected rides as closed"
|
||||
|
||||
def mark_as_under_maintenance(self, request, queryset):
|
||||
queryset.update(status='under_maintenance')
|
||||
mark_as_under_maintenance.short_description = "Mark selected rides as under maintenance"
|
||||
|
||||
def mark_as_removed(self, request, queryset):
|
||||
queryset.update(status='removed')
|
||||
mark_as_removed.short_description = "Mark selected rides as removed"
|
||||
|
||||
@admin.register(RollerCoasterStats)
|
||||
class RollerCoasterStatsAdmin(SimpleHistoryAdmin):
|
||||
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 = ('ride',)
|
||||
history_list_display = ['height_ft', 'length_ft', 'speed_mph', 'inversions']
|
||||
|
||||
fieldsets = (
|
||||
('Basic Stats', {
|
||||
'fields': (
|
||||
'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',
|
||||
capacity
|
||||
)
|
||||
return '-'
|
||||
get_capacity.short_description = 'Total Capacity'
|
||||
8
rides/apps.py
Normal file
8
rides/apps.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
class RidesConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'rides'
|
||||
|
||||
def ready(self):
|
||||
import rides.signals # noqa
|
||||
140
rides/migrations/0001_initial.py
Normal file
140
rides/migrations/0001_initial.py
Normal file
@@ -0,0 +1,140 @@
|
||||
# Generated by Django 5.1.2 on 2024-10-28 20:17
|
||||
|
||||
import django.db.models.deletion
|
||||
import simple_history.models
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('companies', '0001_initial'),
|
||||
('parks', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='HistoricalRide',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('slug', models.SlugField(max_length=255)),
|
||||
('description', models.TextField(blank=True)),
|
||||
('category', models.CharField(choices=[('RC', 'Roller Coaster'), ('DR', 'Dark Ride'), ('FR', 'Flat Ride'), ('WR', 'Water Ride'), ('TR', 'Transport'), ('OT', 'Other')], default='OT', max_length=2)),
|
||||
('model_name', models.CharField(blank=True, max_length=255)),
|
||||
('status', models.CharField(choices=[('OPERATING', 'Operating'), ('CLOSED_TEMP', 'Temporarily Closed'), ('CLOSED_PERM', 'Permanently Closed'), ('UNDER_CONSTRUCTION', 'Under Construction'), ('DEMOLISHED', 'Demolished'), ('RELOCATED', 'Relocated')], default='OPERATING', max_length=20)),
|
||||
('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)),
|
||||
('accessibility_options', models.TextField(blank=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(blank=True, editable=False)),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('manufacturer', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='companies.manufacturer')),
|
||||
('park', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_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='+', to='parks.parkarea')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical ride',
|
||||
'verbose_name_plural': 'historical rides',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Ride',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('slug', models.SlugField(max_length=255)),
|
||||
('description', models.TextField(blank=True)),
|
||||
('category', models.CharField(choices=[('RC', 'Roller Coaster'), ('DR', 'Dark Ride'), ('FR', 'Flat Ride'), ('WR', 'Water Ride'), ('TR', 'Transport'), ('OT', 'Other')], default='OT', max_length=2)),
|
||||
('model_name', models.CharField(blank=True, max_length=255)),
|
||||
('status', models.CharField(choices=[('OPERATING', 'Operating'), ('CLOSED_TEMP', 'Temporarily Closed'), ('CLOSED_PERM', 'Permanently Closed'), ('UNDER_CONSTRUCTION', 'Under Construction'), ('DEMOLISHED', 'Demolished'), ('RELOCATED', 'Relocated')], default='OPERATING', max_length=20)),
|
||||
('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)),
|
||||
('accessibility_options', models.TextField(blank=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)),
|
||||
('manufacturer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='rides', to='companies.manufacturer')),
|
||||
('park', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rides', to='parks.park')),
|
||||
('park_area', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='rides', to='parks.parkarea')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['name'],
|
||||
'unique_together': {('park', 'slug')},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalRollerCoasterStats',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, 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)),
|
||||
('launch_type', models.CharField(choices=[('CHAIN', 'Chain Lift'), ('CABLE', 'Cable Launch'), ('HYDRAULIC', 'Hydraulic Launch'), ('LSM', 'Linear Synchronous Motor'), ('LIM', 'Linear Induction Motor'), ('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)),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('ride', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='rides.ride')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Roller Coaster Statistics',
|
||||
'verbose_name_plural': 'historical Roller Coaster Statistics',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
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)),
|
||||
('launch_type', models.CharField(choices=[('CHAIN', 'Chain Lift'), ('CABLE', 'Cable Launch'), ('HYDRAULIC', 'Hydraulic Launch'), ('LSM', 'Linear Synchronous Motor'), ('LIM', 'Linear Induction Motor'), ('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',
|
||||
},
|
||||
),
|
||||
]
|
||||
0
rides/migrations/__init__.py
Normal file
0
rides/migrations/__init__.py
Normal file
BIN
rides/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
BIN
rides/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
rides/migrations/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
rides/migrations/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
155
rides/models.py
Normal file
155
rides/models.py
Normal file
@@ -0,0 +1,155 @@
|
||||
from django.db import models
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.utils.text import slugify
|
||||
from simple_history.models import HistoricalRecords
|
||||
|
||||
class Ride(models.Model):
|
||||
CATEGORY_CHOICES = [
|
||||
('RC', 'Roller Coaster'),
|
||||
('DR', 'Dark Ride'),
|
||||
('FR', 'Flat Ride'),
|
||||
('WR', 'Water Ride'),
|
||||
('TR', 'Transport'),
|
||||
('OT', 'Other'),
|
||||
]
|
||||
|
||||
STATUS_CHOICES = [
|
||||
('OPERATING', 'Operating'),
|
||||
('CLOSED_TEMP', 'Temporarily Closed'),
|
||||
('CLOSED_PERM', 'Permanently Closed'),
|
||||
('UNDER_CONSTRUCTION', 'Under Construction'),
|
||||
('DEMOLISHED', 'Demolished'),
|
||||
('RELOCATED', 'Relocated'),
|
||||
]
|
||||
|
||||
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='OT'
|
||||
)
|
||||
manufacturer = models.ForeignKey(
|
||||
'companies.Manufacturer',
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='rides',
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
model_name = models.CharField(max_length=255, blank=True)
|
||||
status = models.CharField(
|
||||
max_length=20,
|
||||
choices=STATUS_CHOICES,
|
||||
default='OPERATING'
|
||||
)
|
||||
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)
|
||||
accessibility_options = models.TextField(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')
|
||||
history = HistoricalRecords()
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
unique_together = ['park', 'slug']
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} at {self.park.name}"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
self.slug = slugify(self.name)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def get_by_slug(cls, slug):
|
||||
"""Get ride by current or historical slug"""
|
||||
try:
|
||||
return cls.objects.get(slug=slug), False
|
||||
except cls.DoesNotExist:
|
||||
# Check historical slugs
|
||||
history = cls.history.filter(slug=slug).order_by('-history_date').first()
|
||||
if history:
|
||||
return cls.objects.get(id=history.id), True
|
||||
raise cls.DoesNotExist("No ride found with this slug")
|
||||
|
||||
class RollerCoasterStats(models.Model):
|
||||
LAUNCH_CHOICES = [
|
||||
('CHAIN', 'Chain Lift'),
|
||||
('CABLE', 'Cable Launch'),
|
||||
('HYDRAULIC', 'Hydraulic Launch'),
|
||||
('LSM', 'Linear Synchronous Motor'),
|
||||
('LIM', 'Linear Induction Motor'),
|
||||
('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)
|
||||
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)
|
||||
history = HistoricalRecords()
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Roller Coaster Statistics'
|
||||
verbose_name_plural = 'Roller Coaster Statistics'
|
||||
|
||||
def __str__(self):
|
||||
return f"Stats for {self.ride.name}"
|
||||
0
rides/signals.py
Normal file
0
rides/signals.py
Normal file
3
rides/tests.py
Normal file
3
rides/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
9
rides/urls.py
Normal file
9
rides/urls.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = 'rides'
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.RideListView.as_view(), name='ride_list'),
|
||||
path('<slug:park_slug>/<slug:ride_slug>/', views.RideDetailView.as_view(), name='ride_detail'),
|
||||
]
|
||||
70
rides/views.py
Normal file
70
rides/views.py
Normal file
@@ -0,0 +1,70 @@
|
||||
from django.views.generic import DetailView, ListView
|
||||
from django.shortcuts import get_object_or_404
|
||||
from .models import Ride, RollerCoasterStats
|
||||
from parks.models import Park
|
||||
from core.views import SlugRedirectMixin
|
||||
|
||||
class RideDetailView(SlugRedirectMixin, DetailView):
|
||||
model = Ride
|
||||
template_name = 'rides/ride_detail.html'
|
||||
context_object_name = 'ride'
|
||||
slug_url_kwarg = 'ride_slug'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
if queryset is None:
|
||||
queryset = self.get_queryset()
|
||||
park_slug = self.kwargs.get('park_slug')
|
||||
ride_slug = self.kwargs.get('ride_slug')
|
||||
# Try to get by current or historical slug
|
||||
obj, is_old_slug = self.model.get_by_slug(ride_slug)
|
||||
if obj.park.slug != park_slug:
|
||||
raise self.model.DoesNotExist("Park slug doesn't match")
|
||||
return obj
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
if self.object.category == 'RC':
|
||||
context['coaster_stats'] = RollerCoasterStats.objects.filter(ride=self.object).first()
|
||||
return context
|
||||
|
||||
def get_redirect_url_pattern(self):
|
||||
return 'ride_detail'
|
||||
|
||||
def get_redirect_url_kwargs(self):
|
||||
return {
|
||||
'park_slug': self.object.park.slug,
|
||||
'ride_slug': self.object.slug
|
||||
}
|
||||
|
||||
class RideListView(ListView):
|
||||
model = Ride
|
||||
template_name = 'rides/ride_list.html'
|
||||
context_object_name = 'rides'
|
||||
paginate_by = 12
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = Ride.objects.select_related('park', 'coaster_stats')
|
||||
|
||||
# Filter by category if specified
|
||||
category = self.request.GET.get('category')
|
||||
if category:
|
||||
queryset = queryset.filter(category=category)
|
||||
|
||||
# Filter by status if specified
|
||||
status = self.request.GET.get('status')
|
||||
if status:
|
||||
queryset = queryset.filter(status=status)
|
||||
|
||||
# Filter by manufacturer if specified
|
||||
manufacturer = self.request.GET.get('manufacturer')
|
||||
if manufacturer:
|
||||
queryset = queryset.filter(manufacturer=manufacturer)
|
||||
|
||||
return queryset.order_by('name')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['manufacturers'] = Ride.objects.values_list(
|
||||
'manufacturer', flat=True
|
||||
).distinct().order_by('manufacturer')
|
||||
return context
|
||||
Reference in New Issue
Block a user