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
externalPort = 3001
[[ports]]
localPort = 46739
externalPort = 3002
[deployment]
deploymentTarget = "autoscale"
run = [

View File

@@ -373,10 +373,7 @@
<div>
<dt class="text-gray-500 dark:text-gray-400">Designer</dt>
<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 }}
</a>
</dd>
</div>
{% endif %}

View File

@@ -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"] = {
# 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