from django.conf import settings from django.core.cache import cache from django.core.paginator import Paginator from django.db.models import Count, Q, Sum from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.views.generic import DetailView, ListView, TemplateView from .models import Album, Photo, Redir class AlbumsList(ListView): """Displays a paginated list of public albums.""" model = Album template_name = 'gallery/album_list.html' paginate_by = 30 def get_queryset(self): page = self.request.GET.get('page', 1) key = f'album_list_queryset_page_{page}' queryset = cache.get(key) if not queryset: queryset = ( Album.objects.filter(is_public=True) .select_related('cover') .annotate( photo_count=Count('photos'), total_views=Sum('photos__views') ) .order_by('-album_date') ) cache.set(key, queryset, 60 * 5) return queryset def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) page = int(self.request.GET.get('page', 1)) # Canonical_url canonical_url = self.request.build_absolute_uri(reverse('gallery:albums_url')) if page > 1: canonical_url += f'?page={page}' context['canonical_url'] = canonical_url return context class AlbumDetail(DetailView): """Shows a single album and its paginated photos.""" model = Album template_name = 'gallery/album_detail.html' def get_object(self, queryset=None): return get_object_or_404(Album, slug=self.kwargs.get('album_slug')) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) #photos = self.object.photos.all().order_by('taken_at') photos = self.object.photos.all().select_related('album').order_by('taken_at') paginator = Paginator(photos, 30) page_obj = paginator.get_page(self.request.GET.get('page')) # Canonical_url page = int(self.request.GET.get('page', 1)) canonical_url = self.request.build_absolute_uri(self.object.get_absolute_url()) if page > 1: canonical_url += f'?page={page}' context.update({ 'photos': page_obj.object_list, 'page_obj': page_obj, 'canonical_url': canonical_url, }) return context class PhotosList(ListView): """Shows all public photos sorted by user-selected ordering.""" model = Photo paginate_by = 30 def get_queryset(self): ordering_options = { 'latest': '-taken_at', 'liked': 'likes', 'popular': '-views' } order = ordering_options.get(self.request.GET.get('order', 'latest'), '-taken_at') return Photo.objects.filter(album__is_public=True).order_by(order).select_related('album') def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['order'] = self.request.GET.get('order', 'latest') context['canonical_url'] = self.request.build_absolute_uri(reverse('gallery:photos_url')) return context class PhotoDetail(DetailView): """Shows a single photo and handles liking functionality.""" model = Photo slug_url_kwarg = 'photo_slug' template_name = 'gallery/photo_detail.html' def get_object(self, queryset=None): album_slug = self.kwargs.get('album_slug') photo_slug = self.kwargs.get('photo_slug') #photo = get_object_or_404(Photo, slug=photo_slug, album__slug=album_slug) photo = get_object_or_404(Photo.objects.select_related('album'), slug=photo_slug, album__slug=album_slug) # Track views using session to avoid duplicate counts if photo.slug not in self.request.session: photo.add_view() self.request.session[photo.slug] = 0 return photo def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({ "next": self.object.get_next(), "prev": self.object.get_prev(), "canonical_url": self.request.build_absolute_uri(self.object.get_absolute_url()), }) return context def post(self, request, *args, **kwargs): photo = self.get_object() if request.POST.get("like") == "true" and self.request.session.get(photo.slug) == 0: photo.add_like() self.request.session[photo.slug] = 1 if request.user.is_authenticated: photo.is_favorite = True photo.save() return redirect('gallery:photo_url', album_slug=self.kwargs['album_slug'], photo_slug=self.kwargs['photo_slug']) class Search(TemplateView): """Search view for public albums by name, place or city.""" template_name = "gallery/search.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) query = self.request.GET.get('q', '').strip() context['query'] = query results = Album.objects.none() if query: results = Album.objects.filter( Q(is_public=True), Q(name__icontains=query) | Q(location__place__icontains=query) | Q(location__city__name__icontains=query) ).order_by('-album_date').distinct() paginator = Paginator(results, 30) page_obj = paginator.get_page(self.request.GET.get('page')) context.update({ 'results': page_obj.object_list, 'page_obj': page_obj, 'paginator': paginator, 'is_paginated': page_obj.has_other_pages(), 'canonical_url': self.request.build_absolute_uri(reverse('gallery:search_url')) }) return context class About(TemplateView): """Static about page.""" template_name = "gallery/about.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['canonical_url'] = self.request.build_absolute_uri(reverse('gallery:about_url')) return context def redirect_to_album(request, redir_path): """Handles redirect logic for shortened/legacy album URLs.""" redir = get_object_or_404(Redir, path=redir_path) return redirect('gallery:album_url', album_slug=redir.album.slug)