Files
thrillwiki_django_no_react/core/views/search.py
pacnpal 66ed4347a9 Refactor test utilities and enhance ASGI settings
- Cleaned up and standardized assertions in ApiTestMixin for API response validation.
- Updated ASGI settings to use os.environ for setting the DJANGO_SETTINGS_MODULE.
- Removed unused imports and improved formatting in settings.py.
- Refactored URL patterns in urls.py for better readability and organization.
- Enhanced view functions in views.py for consistency and clarity.
- Added .flake8 configuration for linting and style enforcement.
- Introduced type stubs for django-environ to improve type checking with Pylance.
2025-08-20 19:51:59 -04:00

179 lines
6.0 KiB
Python

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)