from django.views.generic import TemplateView from django.http import JsonResponse from django.contrib.gis.geos import Point from django.contrib.gis.measure import Distance from parks.models import Park from parks.filters import ParkFilter from core.services.location_search import location_search_service, LocationSearchFilters from core.forms.search import LocationSearchForm class AdaptiveSearchView(TemplateView): template_name = "core/search/results.html" def get_queryset(self): """ Get the base queryset, optimized with select_related and prefetch_related """ return Park.objects.select_related('operator', 'property_owner').prefetch_related( 'location', 'photos' ).all() def get_filterset(self): """ Get the filterset instance """ return ParkFilter(self.request.GET, queryset=self.get_queryset()) def get_context_data(self, **kwargs): """ Add filtered results and filter form to context """ context = super().get_context_data(**kwargs) filterset = self.get_filterset() # Check if location-based search is being used location_search = self.request.GET.get('location_search', '').strip() near_location = self.request.GET.get('near_location', '').strip() # Add location search context context.update({ 'results': filterset.qs, 'filters': filterset, 'applied_filters': bool(self.request.GET), # Check if any filters are applied 'is_location_search': bool(location_search or near_location), 'location_search_query': location_search or near_location, }) return context class FilterFormView(TemplateView): """ View for rendering just the filter form for HTMX updates """ template_name = "core/search/filters.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) filterset = ParkFilter(self.request.GET, queryset=Park.objects.all()) context['filters'] = filterset return context class LocationSearchView(TemplateView): """ Enhanced search view with comprehensive location search capabilities. """ template_name = "core/search/location_results.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # Build search filters from request parameters filters = self._build_search_filters() # Perform search results = location_search_service.search(filters) # Group results by type for better presentation grouped_results = { 'parks': [r for r in results if r.content_type == 'park'], 'rides': [r for r in results if r.content_type == 'ride'], 'companies': [r for r in results if r.content_type == 'company'], } context.update({ 'results': results, 'grouped_results': grouped_results, 'total_results': len(results), 'search_filters': filters, 'has_location_filter': bool(filters.location_point), 'search_form': LocationSearchForm(self.request.GET), }) return context def _build_search_filters(self) -> LocationSearchFilters: """Build LocationSearchFilters from request parameters.""" form = LocationSearchForm(self.request.GET) form.is_valid() # Populate cleaned_data # Parse location coordinates if provided location_point = None lat = form.cleaned_data.get('lat') lng = form.cleaned_data.get('lng') if lat and lng: try: location_point = Point(float(lng), float(lat), srid=4326) except (ValueError, TypeError): location_point = None # Parse location types location_types = set() if form.cleaned_data.get('search_parks'): location_types.add('park') if form.cleaned_data.get('search_rides'): location_types.add('ride') if form.cleaned_data.get('search_companies'): location_types.add('company') # If no specific types selected, search all if not location_types: location_types = {'park', 'ride', 'company'} # Parse radius radius_km = None radius_str = form.cleaned_data.get('radius_km', '').strip() if radius_str: try: radius_km = float(radius_str) radius_km = max(1, min(500, radius_km)) # Clamp between 1-500km except (ValueError, TypeError): radius_km = None return LocationSearchFilters( search_query=form.cleaned_data.get('q', '').strip() or None, location_point=location_point, radius_km=radius_km, location_types=location_types if location_types else None, country=form.cleaned_data.get('country', '').strip() or None, state=form.cleaned_data.get('state', '').strip() or None, city=form.cleaned_data.get('city', '').strip() or None, park_status=self.request.GET.getlist('park_status') or None, include_distance=True, max_results=int(self.request.GET.get('limit', 100)) ) class LocationSuggestionsView(TemplateView): """ AJAX endpoint for location search suggestions. """ def get(self, request, *args, **kwargs): query = request.GET.get('q', '').strip() limit = int(request.GET.get('limit', 10)) if len(query) < 2: return JsonResponse({'suggestions': []}) try: suggestions = location_search_service.suggest_locations(query, limit) return JsonResponse({'suggestions': suggestions}) except Exception as e: return JsonResponse({'error': str(e)}, status=500)