from django.views.generic import TemplateView from django.http import JsonResponse from django.contrib.gis.geos import Point 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) # Clamp between 1-500km radius_km = max(1, min(500, radius_km)) 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)