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
This commit is contained in:
pac7
2025-09-22 15:45:51 +00:00
parent cb3a9ddf3f
commit 95f94cc799
3 changed files with 69 additions and 16 deletions

View File

@@ -62,6 +62,10 @@ externalPort = 3000
localPort = 45245 localPort = 45245
externalPort = 3001 externalPort = 3001
[[ports]]
localPort = 46739
externalPort = 3002
[deployment] [deployment]
deploymentTarget = "autoscale" deploymentTarget = "autoscale"
run = [ run = [

View File

@@ -373,10 +373,7 @@
<div> <div>
<dt class="text-gray-500 dark:text-gray-400">Designer</dt> <dt class="text-gray-500 dark:text-gray-400">Designer</dt>
<dd class="font-medium text-gray-900 dark:text-white"> <dd class="font-medium text-gray-900 dark:text-white">
<a href="{% url 'designers:designer_detail' ride.designer.slug %}"
class="text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300">
{{ ride.designer.name }} {{ ride.designer.name }}
</a>
</dd> </dd>
</div> </div>
{% endif %} {% endif %}

View File

@@ -6,8 +6,28 @@ from apps.parks.models import Park, Company
from apps.rides.models import Ride from apps.rides.models import Ride
from apps.core.analytics import PageView from apps.core.analytics import PageView
from django.conf import settings from django.conf import settings
from django.db import connection
import os import os
import secrets 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): def handler404(request, exception):
@@ -22,14 +42,22 @@ class HomeView(TemplateView):
template_name = "home.html" template_name = "home.html"
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
# Track query count for performance monitoring
queries_start = len(connection.queries)
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
# Get stats # Get stats - try cache first
context["stats"] = { stats = cache.get("homepage_stats")
if stats is None:
stats = {
"total_parks": Park.objects.count(), "total_parks": Park.objects.count(),
"ride_count": Ride.objects.count(), "ride_count": Ride.objects.count(),
"coaster_count": Ride.objects.filter(category="RC").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 # Try to get trending items from cache first
trending_parks = cache.get("trending_parks") trending_parks = cache.get("trending_parks")
@@ -38,9 +66,11 @@ class HomeView(TemplateView):
# If not in cache, get them directly and cache them # If not in cache, get them directly and cache them
if trending_parks is None: if trending_parks is None:
try: 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) PageView.get_trending_items(Park, hours=24, limit=10)
) )
trending_parks = list(trending_parks_qs)
# Filter out any parks with invalid slugs # Filter out any parks with invalid slugs
trending_parks = [p for p in trending_parks if getattr(p, 'slug', None)] trending_parks = [p for p in trending_parks if getattr(p, 'slug', None)]
if trending_parks: if trending_parks:
@@ -51,18 +81,24 @@ class HomeView(TemplateView):
# Fallback to highest rated parks if no trending data # Fallback to highest rated parks if no trending data
trending_parks = Park.objects.exclude( trending_parks = Park.objects.exclude(
average_rating__isnull=True 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: except Exception:
# Fallback to highest rated parks if trending calculation fails # Fallback to highest rated parks if trending calculation fails
trending_parks = Park.objects.exclude( trending_parks = Park.objects.exclude(
average_rating__isnull=True 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: if trending_rides is None:
try: 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) PageView.get_trending_items(Ride, hours=24, limit=10)
) )
trending_rides = list(trending_rides_qs)
# Filter out any rides with invalid slugs # Filter out any rides with invalid slugs
trending_rides = [r for r in trending_rides if getattr(r, 'slug', None)] trending_rides = [r for r in trending_rides if getattr(r, 'slug', None)]
if trending_rides: if trending_rides:
@@ -73,23 +109,34 @@ class HomeView(TemplateView):
# Fallback to highest rated rides if no trending data # Fallback to highest rated rides if no trending data
trending_rides = Ride.objects.exclude( trending_rides = Ride.objects.exclude(
average_rating__isnull=True 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: except Exception:
# Fallback to highest rated rides if trending calculation fails # Fallback to highest rated rides if trending calculation fails
trending_rides = Ride.objects.exclude( trending_rides = Ride.objects.exclude(
average_rating__isnull=True 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) # Get highest rated items (mix of parks and rides)
highest_rated_parks = list( highest_rated_parks = list(
Park.objects.exclude(average_rating__isnull=True) Park.objects.exclude(average_rating__isnull=True)
.exclude(slug__isnull=True).exclude(slug__exact='') .exclude(slug__isnull=True).exclude(slug__exact='')
.select_related('operator', 'property_owner', 'card_image', 'banner_image')
.prefetch_related('photos')
.order_by("-average_rating")[:20] .order_by("-average_rating")[:20]
) # Get more items to randomly select from ) # Get more items to randomly select from
highest_rated_rides = list( highest_rated_rides = list(
Ride.objects.exclude(average_rating__isnull=True) Ride.objects.exclude(average_rating__isnull=True)
.exclude(slug__isnull=True).exclude(slug__exact='') .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] .order_by("-average_rating")[:20]
) # Get more items to randomly select from ) # Get more items to randomly select from
@@ -104,6 +151,11 @@ class HomeView(TemplateView):
:10 :10
] # Take first 10 after shuffling ] # 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 return context