mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 17:11:09 -05:00
302 lines
9.6 KiB
Python
302 lines
9.6 KiB
Python
"""
|
|
Custom managers and QuerySets for Rides models.
|
|
Optimized queries following Django styleguide patterns.
|
|
"""
|
|
|
|
from typing import Optional, List, Union
|
|
from django.db.models import Q, F, Count, Prefetch
|
|
|
|
from apps.core.managers import (
|
|
BaseQuerySet,
|
|
BaseManager,
|
|
ReviewableQuerySet,
|
|
ReviewableManager,
|
|
StatusQuerySet,
|
|
StatusManager,
|
|
)
|
|
|
|
|
|
class RideQuerySet(StatusQuerySet, ReviewableQuerySet):
|
|
"""Optimized QuerySet for Ride model."""
|
|
|
|
def by_category(self, *, category: Union[str, List[str]]):
|
|
"""Filter rides by category."""
|
|
if isinstance(category, list):
|
|
return self.filter(category__in=category)
|
|
return self.filter(category=category)
|
|
|
|
def coasters(self):
|
|
"""Filter for roller coasters."""
|
|
return self.filter(category__in=["RC", "WC"])
|
|
|
|
def thrill_rides(self):
|
|
"""Filter for thrill rides."""
|
|
return self.filter(category__in=["RC", "WC", "FR"])
|
|
|
|
def family_friendly(self, *, max_height_requirement: int = 42):
|
|
"""Filter for family-friendly rides."""
|
|
return self.filter(
|
|
Q(min_height_in__lte=max_height_requirement) | Q(min_height_in__isnull=True)
|
|
)
|
|
|
|
def by_park(self, *, park_id: int):
|
|
"""Filter rides by park."""
|
|
return self.filter(park_id=park_id)
|
|
|
|
def by_manufacturer(self, *, manufacturer_id: int):
|
|
"""Filter rides by manufacturer."""
|
|
return self.filter(manufacturer_id=manufacturer_id)
|
|
|
|
def by_designer(self, *, designer_id: int):
|
|
"""Filter rides by designer."""
|
|
return self.filter(designer_id=designer_id)
|
|
|
|
def with_capacity_info(self):
|
|
"""Add capacity-related annotations."""
|
|
return self.annotate(
|
|
estimated_daily_capacity=F("capacity_per_hour")
|
|
* 10, # Assuming 10 operating hours
|
|
duration_minutes=F("ride_duration_seconds") / 60.0,
|
|
)
|
|
|
|
def high_capacity(self, *, min_capacity: int = 1000):
|
|
"""Filter for high-capacity rides."""
|
|
return self.filter(capacity_per_hour__gte=min_capacity)
|
|
|
|
def optimized_for_list(self):
|
|
"""Optimize for ride list display."""
|
|
return self.select_related(
|
|
"park", "park_area", "manufacturer", "designer", "ride_model"
|
|
).with_review_stats()
|
|
|
|
def optimized_for_detail(self):
|
|
"""Optimize for ride detail display."""
|
|
from .models import RideReview
|
|
|
|
return self.select_related(
|
|
"park",
|
|
"park_area",
|
|
"manufacturer",
|
|
"designer",
|
|
"ride_model__manufacturer",
|
|
).prefetch_related(
|
|
"location",
|
|
"rollercoaster_stats",
|
|
Prefetch(
|
|
"reviews",
|
|
queryset=RideReview.objects.select_related("user")
|
|
.filter(is_published=True)
|
|
.order_by("-created_at")[:10],
|
|
),
|
|
"photos",
|
|
)
|
|
|
|
def for_map_display(self):
|
|
"""Optimize for map display."""
|
|
return (
|
|
self.select_related("park", "park_area")
|
|
.prefetch_related("location")
|
|
.values(
|
|
"id",
|
|
"name",
|
|
"slug",
|
|
"category",
|
|
"status",
|
|
"park__name",
|
|
"park__slug",
|
|
"park_area__name",
|
|
"location__point",
|
|
)
|
|
)
|
|
|
|
def search_by_specs(
|
|
self,
|
|
*,
|
|
min_height: Optional[int] = None,
|
|
max_height: Optional[int] = None,
|
|
min_speed: Optional[float] = None,
|
|
inversions: Optional[bool] = None,
|
|
):
|
|
"""Search rides by physical specifications."""
|
|
queryset = self
|
|
|
|
if min_height:
|
|
queryset = queryset.filter(
|
|
Q(rollercoaster_stats__height_ft__gte=min_height)
|
|
| Q(min_height_in__gte=min_height)
|
|
)
|
|
|
|
if max_height:
|
|
queryset = queryset.filter(
|
|
Q(rollercoaster_stats__height_ft__lte=max_height)
|
|
| Q(max_height_in__lte=max_height)
|
|
)
|
|
|
|
if min_speed:
|
|
queryset = queryset.filter(rollercoaster_stats__speed_mph__gte=min_speed)
|
|
|
|
if inversions is not None:
|
|
if inversions:
|
|
queryset = queryset.filter(rollercoaster_stats__inversions__gt=0)
|
|
else:
|
|
queryset = queryset.filter(
|
|
Q(rollercoaster_stats__inversions=0)
|
|
| Q(rollercoaster_stats__isnull=True)
|
|
)
|
|
|
|
return queryset
|
|
|
|
|
|
class RideManager(StatusManager, ReviewableManager):
|
|
"""Custom manager for Ride model."""
|
|
|
|
def get_queryset(self):
|
|
return RideQuerySet(self.model, using=self._db)
|
|
|
|
def coasters(self):
|
|
return self.get_queryset().coasters()
|
|
|
|
def thrill_rides(self):
|
|
return self.get_queryset().thrill_rides()
|
|
|
|
def family_friendly(self, *, max_height_requirement: int = 42):
|
|
return self.get_queryset().family_friendly(
|
|
max_height_requirement=max_height_requirement
|
|
)
|
|
|
|
def by_park(self, *, park_id: int):
|
|
return self.get_queryset().by_park(park_id=park_id)
|
|
|
|
def high_capacity(self, *, min_capacity: int = 1000):
|
|
return self.get_queryset().high_capacity(min_capacity=min_capacity)
|
|
|
|
def optimized_for_list(self):
|
|
return self.get_queryset().optimized_for_list()
|
|
|
|
def optimized_for_detail(self):
|
|
return self.get_queryset().optimized_for_detail()
|
|
|
|
|
|
class RideModelQuerySet(BaseQuerySet):
|
|
"""QuerySet for RideModel model."""
|
|
|
|
def by_manufacturer(self, *, manufacturer_id: int):
|
|
"""Filter ride models by manufacturer."""
|
|
return self.filter(manufacturer_id=manufacturer_id)
|
|
|
|
def by_category(self, *, category: str):
|
|
"""Filter ride models by category."""
|
|
return self.filter(category=category)
|
|
|
|
def with_ride_counts(self):
|
|
"""Add count of rides using this model."""
|
|
return self.annotate(
|
|
ride_count=Count("rides", distinct=True),
|
|
operating_rides_count=Count(
|
|
"rides", filter=Q(rides__status="OPERATING"), distinct=True
|
|
),
|
|
)
|
|
|
|
def popular_models(self, *, min_installations: int = 5):
|
|
"""Filter for popular ride models."""
|
|
return self.with_ride_counts().filter(ride_count__gte=min_installations)
|
|
|
|
def optimized_for_list(self):
|
|
"""Optimize for model list display."""
|
|
return self.select_related("manufacturer").with_ride_counts()
|
|
|
|
|
|
class RideModelManager(BaseManager):
|
|
"""Manager for RideModel model."""
|
|
|
|
def get_queryset(self):
|
|
return RideModelQuerySet(self.model, using=self._db)
|
|
|
|
def by_manufacturer(self, *, manufacturer_id: int):
|
|
return self.get_queryset().by_manufacturer(manufacturer_id=manufacturer_id)
|
|
|
|
def popular_models(self, *, min_installations: int = 5):
|
|
return self.get_queryset().popular_models(min_installations=min_installations)
|
|
|
|
|
|
class RideReviewQuerySet(ReviewableQuerySet):
|
|
"""QuerySet for RideReview model."""
|
|
|
|
def for_ride(self, *, ride_id: int):
|
|
"""Filter reviews for a specific ride."""
|
|
return self.filter(ride_id=ride_id)
|
|
|
|
def by_user(self, *, user_id: int):
|
|
"""Filter reviews by user."""
|
|
return self.filter(user_id=user_id)
|
|
|
|
def by_rating_range(self, *, min_rating: int = 1, max_rating: int = 10):
|
|
"""Filter reviews by rating range."""
|
|
return self.filter(rating__gte=min_rating, rating__lte=max_rating)
|
|
|
|
def optimized_for_display(self):
|
|
"""Optimize for review display."""
|
|
return self.select_related("user", "ride", "moderated_by")
|
|
|
|
|
|
class RideReviewManager(BaseManager):
|
|
"""Manager for RideReview model."""
|
|
|
|
def get_queryset(self):
|
|
return RideReviewQuerySet(self.model, using=self._db)
|
|
|
|
def for_ride(self, *, ride_id: int):
|
|
return self.get_queryset().for_ride(ride_id=ride_id)
|
|
|
|
def by_rating_range(self, *, min_rating: int = 1, max_rating: int = 10):
|
|
return self.get_queryset().by_rating_range(
|
|
min_rating=min_rating, max_rating=max_rating
|
|
)
|
|
|
|
|
|
class RollerCoasterStatsQuerySet(BaseQuerySet):
|
|
"""QuerySet for RollerCoasterStats model."""
|
|
|
|
def tall_coasters(self, *, min_height_ft: float = 200):
|
|
"""Filter for tall roller coasters."""
|
|
return self.filter(height_ft__gte=min_height_ft)
|
|
|
|
def fast_coasters(self, *, min_speed_mph: float = 60):
|
|
"""Filter for fast roller coasters."""
|
|
return self.filter(speed_mph__gte=min_speed_mph)
|
|
|
|
def with_inversions(self):
|
|
"""Filter for coasters with inversions."""
|
|
return self.filter(inversions__gt=0)
|
|
|
|
def launched_coasters(self):
|
|
"""Filter for launched coasters."""
|
|
return self.exclude(propulsion_system="NONE")
|
|
|
|
def by_track_type(self, *, track_type: str):
|
|
"""Filter by track type."""
|
|
return self.filter(track_type=track_type)
|
|
|
|
def optimized_for_list(self):
|
|
"""Optimize for stats list display."""
|
|
return self.select_related("ride", "ride__park")
|
|
|
|
|
|
class RollerCoasterStatsManager(BaseManager):
|
|
"""Manager for RollerCoasterStats model."""
|
|
|
|
def get_queryset(self):
|
|
return RollerCoasterStatsQuerySet(self.model, using=self._db)
|
|
|
|
def tall_coasters(self, *, min_height_ft: float = 200):
|
|
return self.get_queryset().tall_coasters(min_height_ft=min_height_ft)
|
|
|
|
def fast_coasters(self, *, min_speed_mph: float = 60):
|
|
return self.get_queryset().fast_coasters(min_speed_mph=min_speed_mph)
|
|
|
|
def with_inversions(self):
|
|
return self.get_queryset().with_inversions()
|
|
|
|
def launched_coasters(self):
|
|
return self.get_queryset().launched_coasters()
|