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.
317 lines
8.3 KiB
Python
317 lines
8.3 KiB
Python
"""
|
|
Selectors for ride-related data retrieval.
|
|
Following Django styleguide pattern for separating data access from business logic.
|
|
"""
|
|
|
|
from typing import Optional, Dict, Any, List
|
|
from django.db.models import QuerySet, Q, F, Count, Avg, Prefetch
|
|
from django.contrib.gis.geos import Point
|
|
from django.contrib.gis.measure import Distance
|
|
|
|
from .models import Ride, RideModel, RideReview
|
|
from parks.models import Park
|
|
|
|
|
|
def ride_list_for_display(*, filters: Optional[Dict[str, Any]] = None) -> QuerySet[Ride]:
|
|
"""
|
|
Get rides optimized for list display with related data.
|
|
|
|
Args:
|
|
filters: Optional dictionary of filter parameters
|
|
|
|
Returns:
|
|
QuerySet of rides with optimized queries
|
|
"""
|
|
queryset = Ride.objects.select_related(
|
|
'park',
|
|
'park__operator',
|
|
'manufacturer',
|
|
'designer',
|
|
'ride_model',
|
|
'park_area'
|
|
).prefetch_related(
|
|
'park__location',
|
|
'location'
|
|
).annotate(
|
|
average_rating_calculated=Avg('reviews__rating')
|
|
)
|
|
|
|
if filters:
|
|
if 'status' in filters:
|
|
queryset = queryset.filter(status=filters['status'])
|
|
if 'category' in filters:
|
|
queryset = queryset.filter(category=filters['category'])
|
|
if 'manufacturer' in filters:
|
|
queryset = queryset.filter(manufacturer=filters['manufacturer'])
|
|
if 'park' in filters:
|
|
queryset = queryset.filter(park=filters['park'])
|
|
if 'search' in filters:
|
|
search_term = filters['search']
|
|
queryset = queryset.filter(
|
|
Q(name__icontains=search_term) |
|
|
Q(description__icontains=search_term) |
|
|
Q(park__name__icontains=search_term)
|
|
)
|
|
|
|
return queryset.order_by('park__name', 'name')
|
|
|
|
|
|
def ride_detail_optimized(*, slug: str, park_slug: str) -> Ride:
|
|
"""
|
|
Get a single ride with all related data optimized for detail view.
|
|
|
|
Args:
|
|
slug: Ride slug identifier
|
|
park_slug: Park slug for the ride
|
|
|
|
Returns:
|
|
Ride instance with optimized prefetches
|
|
|
|
Raises:
|
|
Ride.DoesNotExist: If ride doesn't exist
|
|
"""
|
|
return Ride.objects.select_related(
|
|
'park',
|
|
'park__operator',
|
|
'manufacturer',
|
|
'designer',
|
|
'ride_model',
|
|
'park_area'
|
|
).prefetch_related(
|
|
'park__location',
|
|
'location',
|
|
Prefetch(
|
|
'reviews',
|
|
queryset=RideReview.objects.select_related('user').filter(is_published=True)
|
|
),
|
|
'photos'
|
|
).get(slug=slug, park__slug=park_slug)
|
|
|
|
|
|
def rides_by_category(*, category: str) -> QuerySet[Ride]:
|
|
"""
|
|
Get all rides in a specific category.
|
|
|
|
Args:
|
|
category: Ride category code
|
|
|
|
Returns:
|
|
QuerySet of rides in the category
|
|
"""
|
|
return Ride.objects.filter(
|
|
category=category
|
|
).select_related(
|
|
'park',
|
|
'manufacturer',
|
|
'designer'
|
|
).prefetch_related(
|
|
'park__location'
|
|
).annotate(
|
|
average_rating_calculated=Avg('reviews__rating')
|
|
).order_by('park__name', 'name')
|
|
|
|
|
|
def rides_by_manufacturer(*, manufacturer_id: int) -> QuerySet[Ride]:
|
|
"""
|
|
Get all rides manufactured by a specific company.
|
|
|
|
Args:
|
|
manufacturer_id: Company ID of the manufacturer
|
|
|
|
Returns:
|
|
QuerySet of rides by the manufacturer
|
|
"""
|
|
return Ride.objects.filter(
|
|
manufacturer_id=manufacturer_id
|
|
).select_related(
|
|
'park',
|
|
'manufacturer',
|
|
'ride_model'
|
|
).prefetch_related(
|
|
'park__location'
|
|
).annotate(
|
|
average_rating_calculated=Avg('reviews__rating')
|
|
).order_by('park__name', 'name')
|
|
|
|
|
|
def rides_by_designer(*, designer_id: int) -> QuerySet[Ride]:
|
|
"""
|
|
Get all rides designed by a specific company.
|
|
|
|
Args:
|
|
designer_id: Company ID of the designer
|
|
|
|
Returns:
|
|
QuerySet of rides by the designer
|
|
"""
|
|
return Ride.objects.filter(
|
|
designer_id=designer_id
|
|
).select_related(
|
|
'park',
|
|
'designer',
|
|
'ride_model'
|
|
).prefetch_related(
|
|
'park__location'
|
|
).annotate(
|
|
average_rating_calculated=Avg('reviews__rating')
|
|
).order_by('park__name', 'name')
|
|
|
|
|
|
def rides_in_park(*, park_slug: str) -> QuerySet[Ride]:
|
|
"""
|
|
Get all rides in a specific park.
|
|
|
|
Args:
|
|
park_slug: Slug of the park
|
|
|
|
Returns:
|
|
QuerySet of rides in the park
|
|
"""
|
|
return Ride.objects.filter(
|
|
park__slug=park_slug
|
|
).select_related(
|
|
'manufacturer',
|
|
'designer',
|
|
'ride_model',
|
|
'park_area'
|
|
).prefetch_related(
|
|
'location'
|
|
).annotate(
|
|
average_rating_calculated=Avg('reviews__rating')
|
|
).order_by('park_area__name', 'name')
|
|
|
|
|
|
def rides_near_location(
|
|
*,
|
|
point: Point,
|
|
distance_km: float = 50,
|
|
limit: int = 10
|
|
) -> QuerySet[Ride]:
|
|
"""
|
|
Get rides near a specific geographic location.
|
|
|
|
Args:
|
|
point: Geographic point (longitude, latitude)
|
|
distance_km: Maximum distance in kilometers
|
|
limit: Maximum number of results
|
|
|
|
Returns:
|
|
QuerySet of nearby rides ordered by distance
|
|
"""
|
|
return Ride.objects.filter(
|
|
park__location__coordinates__distance_lte=(point, Distance(km=distance_km))
|
|
).select_related(
|
|
'park',
|
|
'manufacturer'
|
|
).prefetch_related(
|
|
'park__location'
|
|
).distance(point).order_by('distance')[:limit]
|
|
|
|
|
|
def ride_models_with_installations() -> QuerySet[RideModel]:
|
|
"""
|
|
Get ride models that have installations with counts.
|
|
|
|
Returns:
|
|
QuerySet of ride models with installation counts
|
|
"""
|
|
return RideModel.objects.annotate(
|
|
installation_count=Count('rides')
|
|
).filter(
|
|
installation_count__gt=0
|
|
).select_related(
|
|
'manufacturer'
|
|
).order_by('-installation_count', 'name')
|
|
|
|
|
|
def ride_search_autocomplete(*, query: str, limit: int = 10) -> QuerySet[Ride]:
|
|
"""
|
|
Get rides matching a search query for autocomplete functionality.
|
|
|
|
Args:
|
|
query: Search string
|
|
limit: Maximum number of results
|
|
|
|
Returns:
|
|
QuerySet of matching rides for autocomplete
|
|
"""
|
|
return Ride.objects.filter(
|
|
Q(name__icontains=query) |
|
|
Q(park__name__icontains=query) |
|
|
Q(manufacturer__name__icontains=query)
|
|
).select_related(
|
|
'park',
|
|
'manufacturer'
|
|
).prefetch_related(
|
|
'park__location'
|
|
).order_by('park__name', 'name')[:limit]
|
|
|
|
|
|
def rides_with_recent_reviews(*, days: int = 30) -> QuerySet[Ride]:
|
|
"""
|
|
Get rides that have received reviews in the last N days.
|
|
|
|
Args:
|
|
days: Number of days to look back for reviews
|
|
|
|
Returns:
|
|
QuerySet of rides with recent reviews
|
|
"""
|
|
from django.utils import timezone
|
|
from datetime import timedelta
|
|
|
|
cutoff_date = timezone.now() - timedelta(days=days)
|
|
|
|
return Ride.objects.filter(
|
|
reviews__created_at__gte=cutoff_date,
|
|
reviews__is_published=True
|
|
).select_related(
|
|
'park',
|
|
'manufacturer'
|
|
).prefetch_related(
|
|
'park__location'
|
|
).annotate(
|
|
recent_review_count=Count('reviews', filter=Q(reviews__created_at__gte=cutoff_date))
|
|
).order_by('-recent_review_count').distinct()
|
|
|
|
|
|
def ride_statistics_by_category() -> Dict[str, Any]:
|
|
"""
|
|
Get ride statistics grouped by category.
|
|
|
|
Returns:
|
|
Dictionary containing ride statistics by category
|
|
"""
|
|
from .models import CATEGORY_CHOICES
|
|
|
|
stats = {}
|
|
for category_code, category_name in CATEGORY_CHOICES:
|
|
if category_code: # Skip empty choice
|
|
count = Ride.objects.filter(category=category_code).count()
|
|
stats[category_code] = {
|
|
'name': category_name,
|
|
'count': count
|
|
}
|
|
|
|
return stats
|
|
|
|
|
|
def rides_by_opening_year(*, year: int) -> QuerySet[Ride]:
|
|
"""
|
|
Get rides that opened in a specific year.
|
|
|
|
Args:
|
|
year: The opening year
|
|
|
|
Returns:
|
|
QuerySet of rides that opened in the specified year
|
|
"""
|
|
return Ride.objects.filter(
|
|
opening_date__year=year
|
|
).select_related(
|
|
'park',
|
|
'manufacturer'
|
|
).prefetch_related(
|
|
'park__location'
|
|
).order_by('opening_date', 'park__name', 'name')
|