Use ajax for like button

This commit is contained in:
Nyymix 2025-04-21 16:37:06 +03:00
parent 13fdbe4f4a
commit 47b543bbb3
3 changed files with 75 additions and 24 deletions

View file

@ -81,19 +81,16 @@
</div> </div>
<div class="uk-grid-small" uk-grid> <div class="uk-grid-small" uk-grid>
<div class="uk-width-expand" uk-leader>Likes</div> <div class="uk-width-expand" uk-leader>Likes</div>
<div>{{ photo.likes }}</div> <div id="like-count">{{ photo.likes }}</div>
</div> </div>
<div class="uk-grid-small" uk-grid> <div class="uk-grid-small" uk-grid>
<div class="uk-width-expand" uk-leader>Download photo</div> <div class="uk-width-expand" uk-leader>Download photo</div>
<div><a href="{{ photo.photo.url }}">{{ photo.width }}x{{ photo.height }}</a></div> <div><a href="{{ photo.photo.url }}">{{ photo.width }}x{{ photo.height }}</a></div>
</div> </div>
<div class="uk-grid-small" uk-grid> <div class="uk-grid-small" uk-grid>
<form action="{% url 'gallery:photo_url' photo.album.slug photo.slug %}" method="POST" class="uk-form"> <button id="like-button" class="uk-button uk-button-primary">
{% csrf_token %} <span id="heart-icon" uk-icon="icon: heart"></span> <span id="like-text">Like</span>
<button type="submit" name="like" value="true" class="uk-button uk-button-primary">
<span uk-icon="icon: heart"></span> Like
</button> </button>
</form>
</div> </div>
</div> </div>
</div> </div>
@ -137,11 +134,46 @@
</div> </div>
</div> </div>
</div> </div>
<script>
const likeBtn = document.getElementById('like-button');
const likeText = document.getElementById('like-text');
const heartIcon = document.getElementById('heart-icon');
const likeCount = document.getElementById('like-count');
likeBtn.addEventListener('click', function () {
fetch("{% url 'gallery:photo_like_url' photo.album.slug photo.slug %}", {
method: "POST",
headers: {
"X-CSRFToken": "{{ csrf_token }}",
"Content-Type": "application/json",
},
})
.then(response => response.json())
.then(data => {
if (data.success) {
likeCount.innerText = data.likes;
if (data.status === "liked") {
likeText.innerText = "Unlike";
heartIcon.setAttribute("style", "color: red");
} else {
likeText.innerText = "Like";
heartIcon.setAttribute("style", "color: inherit");
}
}
});
});
</script>
{% if liked %}
<script>
document.addEventListener("DOMContentLoaded", function() {
document.getElementById('like-text').innerText = "Unlike";
document.getElementById('heart-icon').setAttribute("style", "color: red");
});
</script>
{% endif %}
{% endblock %} {% endblock %}

View file

@ -13,6 +13,7 @@ urlpatterns = [
path('about/', views.About.as_view(), name='about_url'), path('about/', views.About.as_view(), name='about_url'),
path('search/', views.Search.as_view(), name='search_url'), path('search/', views.Search.as_view(), name='search_url'),
path('photostream/', views.PhotosList.as_view(), name='photos_url'), path('photostream/', views.PhotosList.as_view(), name='photos_url'),
path('like/<slug:album_slug>/<filename:photo_slug>', views.PhotoLike.as_view(), name='photo_like_url'),
path('albums/<path:album_slug>/<filename:photo_slug>', views.PhotoDetail.as_view(), name='photo_url'), path('albums/<path:album_slug>/<filename:photo_slug>', views.PhotoDetail.as_view(), name='photo_url'),
path('albums/<path:album_slug>/', views.AlbumDetail.as_view(), name='album_url'), path('albums/<path:album_slug>/', views.AlbumDetail.as_view(), name='album_url'),
path('albums/', views.AlbumsList.as_view(), name='albums_url'), path('albums/', views.AlbumsList.as_view(), name='albums_url'),

View file

@ -2,8 +2,10 @@ from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.db.models import Count, Q, Sum from django.db.models import Count, Q, Sum
from django.shortcuts import get_object_or_404, redirect, render from django.http import JsonResponse
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse from django.urls import reverse
from django.views import View
from django.views.generic import DetailView, ListView, TemplateView from django.views.generic import DetailView, ListView, TemplateView
from .models import Album, Photo, Redir from .models import Album, Photo, Redir
@ -57,7 +59,7 @@ class AlbumDetail(DetailView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
#photos = self.object.photos.all().order_by('taken_at') # photos = self.object.photos.all().order_by('taken_at')
photos = self.object.photos.all().select_related('album').order_by('taken_at') photos = self.object.photos.all().select_related('album').order_by('taken_at')
paginator = Paginator(photos, 30) paginator = Paginator(photos, 30)
@ -77,7 +79,6 @@ class AlbumDetail(DetailView):
return context return context
class PhotosList(ListView): class PhotosList(ListView):
"""Shows all public photos sorted by user-selected ordering.""" """Shows all public photos sorted by user-selected ordering."""
model = Photo model = Photo
@ -108,7 +109,7 @@ class PhotoDetail(DetailView):
def get_object(self, queryset=None): def get_object(self, queryset=None):
album_slug = self.kwargs.get('album_slug') album_slug = self.kwargs.get('album_slug')
photo_slug = self.kwargs.get('photo_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, slug=photo_slug, album__slug=album_slug)
photo = get_object_or_404(Photo.objects.select_related('album'), 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 # Track views using session to avoid duplicate counts
@ -124,21 +125,37 @@ class PhotoDetail(DetailView):
"next": self.object.get_next(), "next": self.object.get_next(),
"prev": self.object.get_prev(), "prev": self.object.get_prev(),
"canonical_url": self.request.build_absolute_uri(self.object.get_absolute_url()), "canonical_url": self.request.build_absolute_uri(self.object.get_absolute_url()),
"liked": self.request.session.get(f"liked_{self.object.slug}", False)
}) })
return context 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: class PhotoLike(View):
photo.add_like() """Ajax like photo button."""
self.request.session[photo.slug] = 1
def get(self, request, *args, **kwargs):
return JsonResponse({'error': 'This endpoint only supports POST requests.'}, status=405)
def post(self, request, album_slug, photo_slug):
photo = get_object_or_404(Photo.objects.select_related('album'), slug=photo_slug, album__slug=album_slug)
session_key = f"liked_{photo.slug}"
liked = request.session.get(session_key, False)
if not liked:
photo.likes += 1
if request.user.is_authenticated: if request.user.is_authenticated:
photo.is_favorite = True photo.is_favorite = True
photo.save() request.session[session_key] = True
status = "liked"
else:
photo.likes = max(0, photo.likes - 1)
if request.user.is_authenticated:
photo.is_favorite = False
request.session[session_key] = False
status = "unliked"
return redirect('gallery:photo_url', album_slug=self.kwargs['album_slug'], photo_slug=self.kwargs['photo_slug']) photo.save()
return JsonResponse({'success': True, 'likes': photo.likes, 'status': status})
class Search(TemplateView): class Search(TemplateView):
@ -175,6 +192,7 @@ class Search(TemplateView):
class About(TemplateView): class About(TemplateView):
"""Static about page.""" """Static about page."""
template_name = "gallery/about.html" template_name = "gallery/about.html"
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['canonical_url'] = self.request.build_absolute_uri(reverse('gallery:about_url')) context['canonical_url'] = self.request.build_absolute_uri(reverse('gallery:about_url'))