mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 10:11:09 -05:00
Add advanced search and trending parks features; update frontend dependencies and enhance home page layout
This commit is contained in:
@@ -4,6 +4,7 @@ from apps.core.views.search import (
|
||||
FilterFormView,
|
||||
LocationSearchView,
|
||||
LocationSuggestionsView,
|
||||
AdvancedSearchView,
|
||||
)
|
||||
from apps.rides.views import RideSearchView
|
||||
|
||||
@@ -12,6 +13,7 @@ app_name = "search"
|
||||
urlpatterns = [
|
||||
path("parks/", AdaptiveSearchView.as_view(), name="search"),
|
||||
path("parks/filters/", FilterFormView.as_view(), name="filter_form"),
|
||||
path("advanced/", AdvancedSearchView.as_view(), name="advanced"),
|
||||
path("rides/", RideSearchView.as_view(), name="ride_search"),
|
||||
path("rides/results/", RideSearchView.as_view(), name="ride_search_results"),
|
||||
# Location-aware search
|
||||
|
||||
@@ -176,3 +176,43 @@ class LocationSuggestionsView(TemplateView):
|
||||
return JsonResponse({"suggestions": suggestions})
|
||||
except Exception as e:
|
||||
return JsonResponse({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
class AdvancedSearchView(TemplateView):
|
||||
"""Advanced search view with comprehensive filtering options for both parks and rides"""
|
||||
template_name = "core/search/advanced.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
# Import here to avoid circular imports
|
||||
from apps.parks.filters import ParkFilter
|
||||
from apps.rides.filters import RideFilter
|
||||
from apps.parks.models import Park
|
||||
from apps.rides.models.rides import Ride
|
||||
|
||||
# Initialize filtersets for both parks and rides
|
||||
park_filterset = ParkFilter(self.request.GET, queryset=Park.objects.all())
|
||||
ride_filterset = RideFilter(self.request.GET, queryset=Ride.objects.all())
|
||||
|
||||
# Determine what type of search to show based on request parameters
|
||||
search_type = self.request.GET.get('search_type', 'parks') # Default to parks
|
||||
|
||||
context.update({
|
||||
'page_title': 'Advanced Search',
|
||||
'page_description': 'Find exactly what you\'re looking for with our comprehensive search filters.',
|
||||
'search_type': search_type,
|
||||
'park_filters': park_filterset,
|
||||
'ride_filters': ride_filterset,
|
||||
'park_results': park_filterset.qs if search_type == 'parks' else None,
|
||||
'ride_results': ride_filterset.qs if search_type == 'rides' else None,
|
||||
'has_filters': bool(self.request.GET),
|
||||
})
|
||||
|
||||
return context
|
||||
|
||||
def get_template_names(self):
|
||||
"""Return appropriate template for HTMX requests"""
|
||||
if hasattr(self.request, 'htmx') and self.request.htmx:
|
||||
return ["core/search/partials/advanced_results.html"]
|
||||
return [self.template_name]
|
||||
|
||||
@@ -15,6 +15,7 @@ app_name = "parks"
|
||||
urlpatterns = [
|
||||
# Park views with autocomplete search
|
||||
path("", views.ParkListView.as_view(), name="park_list"),
|
||||
path("trending/", views.TrendingParksView.as_view(), name="trending"),
|
||||
path("operators/", views.OperatorListView.as_view(), name="operator_list"),
|
||||
path("create/", views.ParkCreateView.as_view(), name="park_create"),
|
||||
# Add park button endpoint (moved before park detail pattern)
|
||||
|
||||
@@ -29,6 +29,9 @@ from django.urls import reverse
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from decimal import InvalidOperation
|
||||
from django.views.generic import DetailView, ListView, CreateView, UpdateView
|
||||
from django.db.models import Count, Avg, Q
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
import requests
|
||||
from decimal import Decimal, ROUND_DOWN
|
||||
from typing import Any, Optional, cast, Literal, Dict
|
||||
@@ -224,6 +227,56 @@ def reverse_geocode(request: HttpRequest) -> JsonResponse:
|
||||
return JsonResponse({"error": "Geocoding failed"}, status=500)
|
||||
|
||||
|
||||
class TrendingParksView(ListView):
|
||||
"""View for displaying trending/popular parks"""
|
||||
model = Park
|
||||
template_name = "parks/trending_parks.html"
|
||||
context_object_name = "parks"
|
||||
paginate_by = 20
|
||||
|
||||
def get_queryset(self) -> QuerySet[Park]:
|
||||
"""Get trending parks based on ride count, ratings, and recent activity"""
|
||||
# For now, order by a combination of factors that indicate popularity:
|
||||
# 1. Parks with more rides
|
||||
# 2. Higher average ratings
|
||||
# 3. More recent activity (reviews, photos, etc.)
|
||||
thirty_days_ago = timezone.now() - timedelta(days=30)
|
||||
|
||||
return (
|
||||
get_base_park_queryset()
|
||||
.annotate(
|
||||
recent_reviews=Count(
|
||||
'reviews',
|
||||
filter=Q(reviews__created_at__gte=thirty_days_ago)
|
||||
),
|
||||
recent_photos=Count(
|
||||
'photos',
|
||||
filter=Q(photos__created_at__gte=thirty_days_ago)
|
||||
)
|
||||
)
|
||||
.order_by(
|
||||
'-recent_reviews',
|
||||
'-recent_photos',
|
||||
'-ride_count',
|
||||
'-average_rating'
|
||||
)
|
||||
)
|
||||
|
||||
def get_template_names(self) -> list[str]:
|
||||
"""Return appropriate template for HTMX requests"""
|
||||
if self.request.htmx:
|
||||
return ["parks/partials/trending_parks.html"]
|
||||
return [self.template_name]
|
||||
|
||||
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
|
||||
context = super().get_context_data(**kwargs)
|
||||
context.update({
|
||||
'page_title': 'Trending Parks',
|
||||
'page_description': 'Discover the most popular theme parks with recent activity and high ratings.'
|
||||
})
|
||||
return context
|
||||
|
||||
|
||||
class ParkListView(HTMXFilterableMixin, ListView):
|
||||
model = Park
|
||||
template_name = "parks/enhanced_park_list.html"
|
||||
|
||||
@@ -6,6 +6,7 @@ app_name = "rides"
|
||||
urlpatterns = [
|
||||
# Global list views
|
||||
path("", views.RideListView.as_view(), name="global_ride_list"),
|
||||
path("new/", views.NewRidesView.as_view(), name="new"),
|
||||
# Global category views
|
||||
path(
|
||||
"roller-coasters/",
|
||||
|
||||
@@ -302,6 +302,37 @@ class RideListView(ListView):
|
||||
return context
|
||||
|
||||
|
||||
class NewRidesView(ListView):
|
||||
"""View for displaying recently added rides"""
|
||||
model = Ride
|
||||
template_name = "rides/new_rides.html"
|
||||
context_object_name = "rides"
|
||||
paginate_by = 20
|
||||
|
||||
def get_queryset(self):
|
||||
"""Get recently added rides, ordered by creation date"""
|
||||
return (
|
||||
Ride.objects.all()
|
||||
.select_related("park", "ride_model", "ride_model__manufacturer")
|
||||
.prefetch_related("photos")
|
||||
.order_by("-created_at")
|
||||
)
|
||||
|
||||
def get_template_names(self):
|
||||
"""Return appropriate template for HTMX requests"""
|
||||
if hasattr(self.request, "htmx") and self.request.htmx:
|
||||
return ["rides/partials/new_rides.html"]
|
||||
return [self.template_name]
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context.update({
|
||||
'page_title': 'New Attractions',
|
||||
'page_description': 'Discover the latest rides and attractions added to theme parks around the world.'
|
||||
})
|
||||
return context
|
||||
|
||||
|
||||
class SingleCategoryListView(ListView):
|
||||
"""View for displaying rides of a specific category"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user