mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 18:11:08 -05:00
- Implemented extensive test cases for the Parks API, covering endpoints for listing, retrieving, creating, updating, and deleting parks. - Added tests for filtering, searching, and ordering parks in the API. - Created tests for error handling in the API, including malformed JSON and unsupported methods. - Developed model tests for Park, ParkArea, Company, and ParkReview models, ensuring validation and constraints are enforced. - Introduced utility mixins for API and model testing to streamline assertions and enhance test readability. - Included integration tests to validate complete workflows involving park creation, retrieval, updating, and deletion.
282 lines
9.6 KiB
Python
282 lines
9.6 KiB
Python
"""
|
|
Custom managers and QuerySets for Rides models.
|
|
Optimized queries following Django styleguide patterns.
|
|
"""
|
|
|
|
from typing import Optional, List, Dict, Any, Union
|
|
from django.db import models
|
|
from django.db.models import Q, F, Count, Avg, Max, Min, Prefetch
|
|
|
|
from 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()
|