""" 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)