mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 08:51:09 -05:00
feat: complete monorepo structure with frontend and shared resources
- Add complete backend/ directory with full Django application - Add frontend/ directory with Vite + TypeScript setup ready for Next.js - Add comprehensive shared/ directory with: - Complete documentation and memory-bank archives - Media files and avatars (letters, park/ride images) - Deployment scripts and automation tools - Shared types and utilities - Add architecture/ directory with migration guides - Configure pnpm workspace for monorepo development - Update .gitignore to exclude .django_tailwind_cli/ build artifacts - Preserve all historical documentation in shared/docs/memory-bank/ - Set up proper structure for full-stack development with shared resources
This commit is contained in:
301
backend/apps/rides/managers.py
Normal file
301
backend/apps/rides/managers.py
Normal file
@@ -0,0 +1,301 @@
|
||||
"""
|
||||
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(launch_type="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()
|
||||
Reference in New Issue
Block a user