Files
pac7 95f94cc799 Improve site performance and adhere to best practices
Optimize database queries for parks and rides using select_related and prefetch_related, implement caching for homepage stats and trending items, and update the ride detail template to remove unnecessary link wrapping.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 48ecdb60-d0f0-4b75-95c9-34e409ef35fb
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
2025-09-22 15:45:51 +00:00

231 lines
9.0 KiB
Python

from django.shortcuts import render
from django.views.generic import TemplateView
from django.db.models import Q
from django.core.cache import cache
from apps.parks.models import Park, Company
from apps.rides.models import Ride
from apps.core.analytics import PageView
from django.conf import settings
from django.db import connection
import os
import secrets
import logging
# Set up logger for query debugging
logger = logging.getLogger(__name__)
def optimize_park_queryset(queryset):
"""Add proper select_related and prefetch_related to park querysets"""
return queryset.select_related(
'operator', 'property_owner', 'card_image', 'banner_image'
).prefetch_related('photos')
def optimize_ride_queryset(queryset):
"""Add proper select_related and prefetch_related to ride querysets"""
return queryset.select_related(
'park', 'park__operator', 'manufacturer', 'designer', 'card_image',
'ride_model', 'park_area'
).prefetch_related('photos')
def handler404(request, exception):
return render(request, "404.html", status=404)
def handler500(request):
return render(request, "500.html", status=500)
class HomeView(TemplateView):
template_name = "home.html"
def get_context_data(self, **kwargs):
# Track query count for performance monitoring
queries_start = len(connection.queries)
context = super().get_context_data(**kwargs)
# Get stats - try cache first
stats = cache.get("homepage_stats")
if stats is None:
stats = {
"total_parks": Park.objects.count(),
"ride_count": Ride.objects.count(),
"coaster_count": Ride.objects.filter(category="RC").count(),
}
# Cache stats for 30 minutes
cache.set("homepage_stats", stats, 1800)
context["stats"] = stats
# Try to get trending items from cache first
trending_parks = cache.get("trending_parks")
trending_rides = cache.get("trending_rides")
# If not in cache, get them directly and cache them
if trending_parks is None:
try:
# Get trending parks with optimized queries
trending_parks_qs = optimize_park_queryset(
PageView.get_trending_items(Park, hours=24, limit=10)
)
trending_parks = list(trending_parks_qs)
# Filter out any parks with invalid slugs
trending_parks = [p for p in trending_parks if getattr(p, 'slug', None)]
if trending_parks:
cache.set(
"trending_parks", trending_parks, 3600
) # Cache for 1 hour
else:
# Fallback to highest rated parks if no trending data
trending_parks = Park.objects.exclude(
average_rating__isnull=True
).exclude(slug__isnull=True).exclude(slug__exact='').select_related(
'operator', 'property_owner', 'card_image', 'banner_image'
).prefetch_related('photos').order_by("-average_rating")[:10]
except Exception:
# Fallback to highest rated parks if trending calculation fails
trending_parks = Park.objects.exclude(
average_rating__isnull=True
).exclude(slug__isnull=True).exclude(slug__exact='').select_related(
'operator', 'property_owner', 'card_image', 'banner_image'
).prefetch_related('photos').order_by("-average_rating")[:10]
if trending_rides is None:
try:
# Get trending rides with optimized queries
trending_rides_qs = optimize_ride_queryset(
PageView.get_trending_items(Ride, hours=24, limit=10)
)
trending_rides = list(trending_rides_qs)
# Filter out any rides with invalid slugs
trending_rides = [r for r in trending_rides if getattr(r, 'slug', None)]
if trending_rides:
cache.set(
"trending_rides", trending_rides, 3600
) # Cache for 1 hour
else:
# Fallback to highest rated rides if no trending data
trending_rides = Ride.objects.exclude(
average_rating__isnull=True
).exclude(slug__isnull=True).exclude(slug__exact='').select_related(
'park', 'park__operator', 'manufacturer', 'designer', 'card_image',
'ride_model', 'park_area'
).prefetch_related('photos').order_by("-average_rating")[:10]
except Exception:
# Fallback to highest rated rides if trending calculation fails
trending_rides = Ride.objects.exclude(
average_rating__isnull=True
).exclude(slug__isnull=True).exclude(slug__exact='').select_related(
'park', 'park__operator', 'manufacturer', 'designer', 'card_image',
'ride_model', 'park_area'
).prefetch_related('photos').order_by("-average_rating")[:10]
# Get highest rated items (mix of parks and rides)
highest_rated_parks = list(
Park.objects.exclude(average_rating__isnull=True)
.exclude(slug__isnull=True).exclude(slug__exact='')
.select_related('operator', 'property_owner', 'card_image', 'banner_image')
.prefetch_related('photos')
.order_by("-average_rating")[:20]
) # Get more items to randomly select from
highest_rated_rides = list(
Ride.objects.exclude(average_rating__isnull=True)
.exclude(slug__isnull=True).exclude(slug__exact='')
.select_related('park', 'park__operator', 'manufacturer', 'designer', 'card_image',
'ride_model', 'park_area')
.prefetch_related('photos')
.order_by("-average_rating")[:20]
) # Get more items to randomly select from
# Combine and shuffle highest rated items
all_highest_rated = highest_rated_parks + highest_rated_rides
secrets.SystemRandom().shuffle(all_highest_rated)
# Keep the same context variable names for template compatibility
context["popular_parks"] = trending_parks
context["popular_rides"] = trending_rides
context["highest_rated"] = all_highest_rated[
:10
] # Take first 10 after shuffling
# Log query count for debugging
queries_end = len(connection.queries)
query_count = queries_end - queries_start
logger.info(f"HomeView executed {query_count} queries")
return context
class SearchView(TemplateView):
template_name = "search_results.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if query := self.request.GET.get("q", "").strip():
# Search parks
context["parks"] = (
Park.objects.filter(
Q(name__icontains=query)
| Q(location__icontains=query)
| Q(description__icontains=query)
)
.select_related("operating_company")
.prefetch_related("photos")[:10]
)
# Search rides
context["rides"] = (
Ride.objects.filter(
Q(name__icontains=query)
| Q(description__icontains=query)
| Q(manufacturer__name__icontains=query)
)
.select_related("park", "coaster_stats")
.prefetch_related("photos")[:10]
)
# Search companies
context["companies"] = Company.objects.filter(
Q(name__icontains=query) | Q(description__icontains=query)
).prefetch_related("operated_parks", "owned_parks")[:10]
return context
def environment_and_settings_view(request):
# Get all environment variables
env_vars = dict(os.environ)
# Get all Django settings as a dictionary
settings_vars = {
setting: getattr(settings, setting)
for setting in dir(settings)
if setting.isupper()
}
return render(
request,
"environment_and_settings.html",
{"env_vars": env_vars, "settings_vars": settings_vars},
)
def test_button_comparison(request):
"""
Test view to compare cotton button component with original include version.
Renders a comprehensive test page with all button variants and combinations.
"""
return render(request, "test_button_comparison.html")
def test_auth_modal_comparison(request):
"""
Test view to compare cotton auth modal component with original include version.
Renders a comprehensive test page to verify Alpine.js functionality, styling, and behavior parity.
"""
return render(request, "test_auth_modal_comparison.html")