Files
thrillwiki_django_no_react/backend/apps/parks/managers.py
pacnpal 540f40e689 Revert "update"
This reverts commit 75cc618c2b.
2025-09-21 20:11:00 -04:00

303 lines
9.5 KiB
Python

"""
Custom managers and QuerySets for Parks models.
Optimized queries following Django styleguide patterns.
"""
from django.db.models import Q, Count, Avg, Max, Min, Prefetch
from apps.core.managers import (
BaseQuerySet,
BaseManager,
LocationQuerySet,
LocationManager,
ReviewableQuerySet,
ReviewableManager,
StatusQuerySet,
StatusManager,
)
class ParkQuerySet(StatusQuerySet, ReviewableQuerySet, LocationQuerySet):
"""Optimized QuerySet for Park model."""
def with_complete_stats(self):
"""Add comprehensive park statistics."""
return self.annotate(
ride_count_calculated=Count("rides", distinct=True),
coaster_count_calculated=Count(
"rides",
filter=Q(rides__category__in=["RC", "WC"]),
distinct=True,
),
area_count=Count("areas", distinct=True),
review_count=Count(
"reviews", filter=Q(reviews__is_published=True), distinct=True
),
average_rating_calculated=Avg(
"reviews__rating", filter=Q(reviews__is_published=True)
),
latest_ride_opening=Max("rides__opening_date"),
oldest_ride_opening=Min("rides__opening_date"),
)
def optimized_for_list(self):
"""Optimize for park list display."""
return (
self.select_related("operator", "property_owner")
.prefetch_related("location")
.with_complete_stats()
)
def optimized_for_detail(self):
"""Optimize for park detail display."""
from apps.rides.models import Ride
from .models import ParkReview
return self.select_related("operator", "property_owner").prefetch_related(
"location",
"areas",
Prefetch(
"rides",
queryset=Ride.objects.select_related(
"manufacturer", "designer", "ride_model", "park_area"
).order_by("name"),
),
Prefetch(
"reviews",
queryset=ParkReview.objects.select_related("user")
.filter(is_published=True)
.order_by("-created_at")[:10],
),
"photos",
)
def by_operator(self, *, operator_id: int):
"""Filter parks by operator."""
return self.filter(operator_id=operator_id)
def by_property_owner(self, *, owner_id: int):
"""Filter parks by property owner."""
return self.filter(property_owner_id=owner_id)
def with_minimum_coasters(self, *, min_coasters: int = 5):
"""Filter parks with minimum number of coasters."""
return self.with_complete_stats().filter(
coaster_count_calculated__gte=min_coasters
)
def large_parks(self, *, min_acres: float = 100.0):
"""Filter for large parks."""
return self.filter(size_acres__gte=min_acres)
def seasonal_parks(self):
"""Filter for parks with seasonal operation."""
return self.exclude(operating_season__exact="")
def for_map_display(self, *, bounds=None):
"""Optimize for map display with minimal data."""
queryset = self.select_related("operator").prefetch_related("location")
if bounds:
queryset = queryset.within_bounds(
north=bounds.north,
south=bounds.south,
east=bounds.east,
west=bounds.west,
)
return queryset.values(
"id",
"name",
"slug",
"status",
"location__latitude",
"location__longitude",
"location__city",
"location__state",
"location__country",
"operator__name",
)
def search_autocomplete(self, *, query: str, limit: int = 10):
"""Optimized search for autocomplete."""
return (
self.filter(
Q(name__icontains=query)
| Q(location__city__icontains=query)
| Q(location__state__icontains=query)
)
.select_related("operator", "location")
.values(
"id",
"name",
"slug",
"location__city",
"location__state",
"operator__name",
)[:limit]
)
class ParkManager(StatusManager, ReviewableManager, LocationManager):
"""Custom manager for Park model."""
def get_queryset(self):
return ParkQuerySet(self.model, using=self._db)
def with_complete_stats(self):
return self.get_queryset().with_complete_stats()
def optimized_for_list(self):
return self.get_queryset().optimized_for_list()
def optimized_for_detail(self):
return self.get_queryset().optimized_for_detail()
def by_operator(self, *, operator_id: int):
return self.get_queryset().by_operator(operator_id=operator_id)
def large_parks(self, *, min_acres: float = 100.0):
return self.get_queryset().large_parks(min_acres=min_acres)
def for_map_display(self, *, bounds=None):
return self.get_queryset().for_map_display(bounds=bounds)
class ParkAreaQuerySet(BaseQuerySet):
"""QuerySet for ParkArea model."""
def with_ride_counts(self):
"""Add ride count annotations."""
return self.annotate(
ride_count=Count("rides", distinct=True),
coaster_count=Count(
"rides",
filter=Q(rides__category__in=["RC", "WC"]),
distinct=True,
),
)
def optimized_for_list(self):
"""Optimize for area list display."""
return self.select_related("park").with_ride_counts()
def by_park(self, *, park_id: int):
"""Filter areas by park."""
return self.filter(park_id=park_id)
def with_rides(self):
"""Filter areas that have rides."""
return self.filter(rides__isnull=False).distinct()
class ParkAreaManager(BaseManager):
"""Manager for ParkArea model."""
def get_queryset(self):
return ParkAreaQuerySet(self.model, using=self._db)
def with_ride_counts(self):
return self.get_queryset().with_ride_counts()
def by_park(self, *, park_id: int):
return self.get_queryset().by_park(park_id=park_id)
class ParkReviewQuerySet(ReviewableQuerySet):
"""QuerySet for ParkReview model."""
def for_park(self, *, park_id: int):
"""Filter reviews for a specific park."""
return self.filter(park_id=park_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", "park", "moderated_by")
def recent_reviews(self, *, days: int = 30):
"""Get recent reviews."""
return self.recent(days=days)
def moderation_required(self):
"""Filter reviews requiring moderation."""
return self.filter(Q(is_published=False) | Q(moderated_at__isnull=True))
class ParkReviewManager(BaseManager):
"""Manager for ParkReview model."""
def get_queryset(self):
return ParkReviewQuerySet(self.model, using=self._db)
def for_park(self, *, park_id: int):
return self.get_queryset().for_park(park_id=park_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
)
def moderation_required(self):
return self.get_queryset().moderation_required()
class CompanyQuerySet(BaseQuerySet):
"""QuerySet for Company model."""
def operators(self):
"""Filter for companies that operate parks."""
return self.filter(roles__contains=["OPERATOR"])
def property_owners(self):
"""Filter for companies that own park properties."""
return self.filter(roles__contains=["PROPERTY_OWNER"])
def manufacturers(self):
"""Filter for ride manufacturers."""
return self.filter(roles__contains=["MANUFACTURER"])
def with_park_counts(self):
"""Add park count annotations."""
return self.annotate(
operated_parks_count=Count("operated_parks", distinct=True),
owned_parks_count=Count("owned_parks", distinct=True),
total_parks_involvement=Count("operated_parks", distinct=True)
+ Count("owned_parks", distinct=True),
)
def major_operators(self, *, min_parks: int = 5):
"""Filter for major park operators."""
return (
self.operators()
.with_park_counts()
.filter(operated_parks_count__gte=min_parks)
)
def optimized_for_list(self):
"""Optimize for company list display."""
return self.with_park_counts()
class CompanyManager(BaseManager):
"""Manager for Company model."""
def get_queryset(self):
return CompanyQuerySet(self.model, using=self._db)
def operators(self):
return self.get_queryset().operators()
def manufacturers(self):
return self.get_queryset().manufacturers()
def major_operators(self, *, min_parks: int = 5):
return self.get_queryset().major_operators(min_parks=min_parks)