""" Park search autocomplete views for enhanced search functionality. Provides fast, cached autocomplete suggestions for park search. """ from typing import Dict, List, Any from django.http import JsonResponse from django.views import View from django.core.cache import cache from django.db.models import Q from django.utils.decorators import method_decorator from django.views.decorators.cache import cache_page from .models import Park from .models.companies import Company from .services.filter_service import ParkFilterService class ParkAutocompleteView(View): """ Provides autocomplete suggestions for park search. Returns JSON with park names, operators, and location suggestions. """ def get(self, request): """Handle GET request for autocomplete suggestions.""" query = request.GET.get('q', '').strip() if len(query) < 2: return JsonResponse({ 'suggestions': [], 'message': 'Type at least 2 characters to search' }) # Check cache first cache_key = f"park_autocomplete:{query.lower()}" cached_result = cache.get(cache_key) if cached_result: return JsonResponse(cached_result) # Generate suggestions suggestions = self._get_suggestions(query) # Cache results for 5 minutes result = { 'suggestions': suggestions, 'query': query } cache.set(cache_key, result, 300) return JsonResponse(result) def _get_suggestions(self, query: str) -> List[Dict[str, Any]]: """Generate autocomplete suggestions based on query.""" suggestions = [] # Park name suggestions (top 5) park_suggestions = self._get_park_suggestions(query) suggestions.extend(park_suggestions) # Operator suggestions (top 3) operator_suggestions = self._get_operator_suggestions(query) suggestions.extend(operator_suggestions) # Location suggestions (top 3) location_suggestions = self._get_location_suggestions(query) suggestions.extend(location_suggestions) # Remove duplicates and limit results seen = set() unique_suggestions = [] for suggestion in suggestions: key = suggestion['name'].lower() if key not in seen: seen.add(key) unique_suggestions.append(suggestion) return unique_suggestions[:10] # Limit to 10 suggestions def _get_park_suggestions(self, query: str) -> List[Dict[str, Any]]: """Get park name suggestions.""" parks = Park.objects.filter( name__icontains=query, status='OPERATING' ).select_related('operator').order_by('name')[:5] suggestions = [] for park in parks: suggestion = { 'name': park.name, 'type': 'park', 'operator': park.operator.name if park.operator else None, 'url': f'/parks/{park.slug}/' if park.slug else None } suggestions.append(suggestion) return suggestions def _get_operator_suggestions(self, query: str) -> List[Dict[str, Any]]: """Get operator suggestions.""" operators = Company.objects.filter( roles__contains=['OPERATOR'], name__icontains=query ).order_by('name')[:3] suggestions = [] for operator in operators: suggestion = { 'name': operator.name, 'type': 'operator', 'park_count': operator.operated_parks.filter(status='OPERATING').count() } suggestions.append(suggestion) return suggestions def _get_location_suggestions(self, query: str) -> List[Dict[str, Any]]: """Get location (city/country) suggestions.""" # Get unique cities city_parks = Park.objects.filter( location__city__icontains=query, status='OPERATING' ).select_related('location').order_by('location__city').distinct()[:2] # Get unique countries country_parks = Park.objects.filter( location__country__icontains=query, status='OPERATING' ).select_related('location').order_by('location__country').distinct()[:2] suggestions = [] # Add city suggestions for park in city_parks: if park.location and park.location.city: city_name = park.location.city if park.location.country: city_name += f", {park.location.country}" suggestion = { 'name': city_name, 'type': 'location', 'location_type': 'city' } suggestions.append(suggestion) # Add country suggestions for park in country_parks: if park.location and park.location.country: suggestion = { 'name': park.location.country, 'type': 'location', 'location_type': 'country' } suggestions.append(suggestion) return suggestions @method_decorator(cache_page(60 * 5), name='dispatch') # Cache for 5 minutes class QuickFilterSuggestionsView(View): """ Provides quick filter suggestions and popular filters. Used for search dropdown quick actions. """ def get(self, request): """Handle GET request for quick filter suggestions.""" filter_service = ParkFilterService() popular_filters = filter_service.get_popular_filters() filter_counts = filter_service.get_filter_counts() return JsonResponse({ 'quick_filters': popular_filters.get('quick_filters', []), 'filter_counts': filter_counts, 'recommended_sorts': popular_filters.get('recommended_sorts', []) })