From 7a419f3b145eba1358da84fe118c0e29d69176d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9DNyymix=E2=80=9D?= Date: Thu, 24 Apr 2025 23:32:12 +0300 Subject: [PATCH] Update and optimize top tags --- gallery/templatetags/top_tags.py | 91 ++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 16 deletions(-) diff --git a/gallery/templatetags/top_tags.py b/gallery/templatetags/top_tags.py index 626a77c..583f48d 100644 --- a/gallery/templatetags/top_tags.py +++ b/gallery/templatetags/top_tags.py @@ -1,3 +1,5 @@ +import random + from django import template from django.core.cache import cache from django.db.models import F @@ -6,19 +8,21 @@ from gallery.models import Album, Photo register = template.Library() - @register.simple_tag def last_albums(count=5): + # Returns the latest public albums, cached for 1 hour. cache_key = f"last_albums_{count}" albums = cache.get(cache_key) if albums is None: albums = Album.objects.filter(is_public=True).order_by("-album_date")[:count] - cache.set(cache_key, albums, timeout=60 * 60) # 1h + cache.set(cache_key, albums, timeout=60 * 60) # 1h return albums @register.simple_tag def top_photos(count=5): + # Returns top photos by is_favorite, likes, and views. + # Uses select_related to reduce DB hits. Cached for 1 hour. cache_key = f"top_photos_{count}" photos = cache.get(cache_key) if photos is None: @@ -28,56 +32,112 @@ def top_photos(count=5): .order_by('-is_favorite', '-likes', '-views') .select_related('album')[:count] ) - cache.set(cache_key, albums, timeout=60 * 60) # 1h + # FIXED: previously cached as 'albums' by mistake + cache.set(cache_key, photos, timeout=60 * 60) return photos @register.simple_tag def random_photos_landscape(count=5): - cache_key = f"random_photos_landscape_{count}" + # Returns random landscape-oriented photos from public albums. + # NO CACHING: always random. + all_ids = list( + Photo.objects + .filter(album__is_public=True, width__gt=F('height')) + .values_list('id', flat=True)[:500] # limit ID pool to improve performance + ) + selected_ids = random.sample(all_ids, min(count, len(all_ids))) + photos = Photo.objects.filter(id__in=selected_ids) + return photos + + +@register.simple_tag +def random_favorite_photos_landscape(count=5): + # Returns random landscape-oriented favorite photos from public albums. + # If fewer than 'count' photos are available, returns an empty list. + # Results are cached for 1 hour for performance. + cache_key = f"random_favorite_photos_landscape_{count}" photos = cache.get(cache_key) if photos is None: - photos = ( - Photo.objects - .filter(album__is_public=True, width__gt=F('height')) - .order_by('?')[:count] + # Get all qualifying photos (landscape, favorite, public) + queryset = Photo.objects.filter( + is_favorite=True, + width__gt=F('height'), + album__is_public=True ) - cache.set(cache_key, photos, timeout=30) # 30 sec + + if queryset.count() < count: + return [] + + # Randomize and take the requested number + photos = queryset.order_by('?')[:count] + cache.set(cache_key, list(photos), timeout=60 * 60) + + return photos + + +@register.simple_tag +def random_favorite_photos_portrait(count=5): + # Returns random portrait-oriented favorite photos from public albums. + # If fewer than 'count' photos are available, returns an empty list. + # Results are cached for 1 hour for performance. + cache_key = f"random_favorite_photos_portrait_{count}" + photos = cache.get(cache_key) + if photos is None: + # Get all qualifying photos (portrait, favorite, public) + queryset = Photo.objects.filter( + is_favorite=True, + height__gt=F('width'), + album__is_public=True + ) + + if queryset.count() < count: + return [] + + photos = queryset.order_by('?')[:count] + cache.set(cache_key, list(photos), timeout=60 * 60) # Cache as list, not queryset + return photos @register.simple_tag def top_photos_landscape(count=5): + # Returns top landscape-oriented photos sorted by views. + # Uses select_related and is cached for 1 hour. cache_key = f"top_photos_landscape_{count}" photos = cache.get(cache_key) - if photos is None: + if photos is None: photos = ( Photo.objects .filter(album__is_public=True, width__gt=F('height')) .order_by('-views') .select_related('album')[:count] ) - cache.set(cache_key, photos, timeout=60 * 60) # 1h + cache.set(cache_key, photos, timeout=60 * 60) return photos @register.simple_tag def top_photos_portrait(count=5): + # Returns top portrait-oriented photos sorted by views. + # Uses select_related and is cached for 1 hour. cache_key = f"top_photos_portrait_{count}" photos = cache.get(cache_key) - if photos is None: + if photos is None: photos = ( Photo.objects .filter(album__is_public=True, height__gt=F('width')) .order_by('-views') .select_related('album')[:count] ) - cache.set(cache_key, photos, timeout=60 * 60) # 1h + cache.set(cache_key, photos, timeout=60 * 60) return photos @register.simple_tag def top_photos_in_album(album, count=5): + # Returns top photos in a specific album by favorite, likes, and views. + # Cached for 1 hour using album.id as cache key part. cache_key = f"top_photos_album_{album.id}_{count}" photos = cache.get(cache_key) if photos is None: @@ -87,6 +147,5 @@ def top_photos_in_album(album, count=5): .order_by('-is_favorite', '-likes', '-views') .select_related('album')[:count] ) - cache.set(cache_key, photos, timeout=60 * 60) # 1h - return photos - + cache.set(cache_key, photos, timeout=60 * 60) + return photos \ No newline at end of file