From 95f94cc7993db71de50f9a651ca5ca4edf4b5114 Mon Sep 17 00:00:00 2001 From: pac7 <47831526-pac7@users.noreply.replit.com> Date: Mon, 22 Sep 2025 15:45:51 +0000 Subject: [PATCH] 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 --- .replit | 4 ++ templates/rides/ride_detail.html | 5 +-- thrillwiki/views.py | 76 +++++++++++++++++++++++++++----- 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/.replit b/.replit index 3520ba63..8f36374f 100644 --- a/.replit +++ b/.replit @@ -62,6 +62,10 @@ externalPort = 3000 localPort = 45245 externalPort = 3001 +[[ports]] +localPort = 46739 +externalPort = 3002 + [deployment] deploymentTarget = "autoscale" run = [ diff --git a/templates/rides/ride_detail.html b/templates/rides/ride_detail.html index 257f3f8a..bf14548f 100644 --- a/templates/rides/ride_detail.html +++ b/templates/rides/ride_detail.html @@ -373,10 +373,7 @@
Designer
- - {{ ride.designer.name }} - + {{ ride.designer.name }}
{% endif %} diff --git a/thrillwiki/views.py b/thrillwiki/views.py index 7618ac6f..98f1fdab 100644 --- a/thrillwiki/views.py +++ b/thrillwiki/views.py @@ -6,8 +6,28 @@ 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): @@ -22,14 +42,22 @@ 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 - context["stats"] = { - "total_parks": Park.objects.count(), - "ride_count": Ride.objects.count(), - "coaster_count": Ride.objects.filter(category="RC").count(), - } + # 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") @@ -38,9 +66,11 @@ class HomeView(TemplateView): # If not in cache, get them directly and cache them if trending_parks is None: try: - trending_parks = list( + # 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: @@ -51,18 +81,24 @@ class HomeView(TemplateView): # 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='').order_by("-average_rating")[:10] + ).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='').order_by("-average_rating")[:10] + ).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: - trending_rides = list( + # 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: @@ -73,23 +109,34 @@ class HomeView(TemplateView): # 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='').order_by("-average_rating")[:10] + ).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='').order_by("-average_rating")[:10] + ).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 @@ -104,6 +151,11 @@ class HomeView(TemplateView): :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