Use ajax for like button
This commit is contained in:
parent
13fdbe4f4a
commit
47b543bbb3
3 changed files with 75 additions and 24 deletions
|
@ -81,19 +81,16 @@
|
|||
</div>
|
||||
<div class="uk-grid-small" uk-grid>
|
||||
<div class="uk-width-expand" uk-leader>Likes</div>
|
||||
<div>{{ photo.likes }}</div>
|
||||
<div id="like-count">{{ photo.likes }}</div>
|
||||
</div>
|
||||
<div class="uk-grid-small" uk-grid>
|
||||
<div class="uk-width-expand" uk-leader>Download photo</div>
|
||||
<div><a href="{{ photo.photo.url }}">{{ photo.width }}x{{ photo.height }}</a></div>
|
||||
</div>
|
||||
<div class="uk-grid-small" uk-grid>
|
||||
<form action="{% url 'gallery:photo_url' photo.album.slug photo.slug %}" method="POST" class="uk-form">
|
||||
{% csrf_token %}
|
||||
<button type="submit" name="like" value="true" class="uk-button uk-button-primary">
|
||||
<span uk-icon="icon: heart"></span> Like
|
||||
<button id="like-button" class="uk-button uk-button-primary">
|
||||
<span id="heart-icon" uk-icon="icon: heart"></span> <span id="like-text">Like</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -137,11 +134,46 @@
|
|||
</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 %}
|
|
@ -13,6 +13,7 @@ urlpatterns = [
|
|||
path('about/', views.About.as_view(), name='about_url'),
|
||||
path('search/', views.Search.as_view(), name='search_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>/', views.AlbumDetail.as_view(), name='album_url'),
|
||||
path('albums/', views.AlbumsList.as_view(), name='albums_url'),
|
||||
|
|
|
@ -2,8 +2,10 @@ 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.http import JsonResponse
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.views import View
|
||||
from django.views.generic import DetailView, ListView, TemplateView
|
||||
|
||||
from .models import Album, Photo, Redir
|
||||
|
@ -33,7 +35,7 @@ class AlbumsList(ListView):
|
|||
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))
|
||||
|
@ -43,7 +45,7 @@ class AlbumsList(ListView):
|
|||
if page > 1:
|
||||
canonical_url += f'?page={page}'
|
||||
context['canonical_url'] = canonical_url
|
||||
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
@ -57,7 +59,7 @@ class AlbumDetail(DetailView):
|
|||
|
||||
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().order_by('taken_at')
|
||||
photos = self.object.photos.all().select_related('album').order_by('taken_at')
|
||||
|
||||
paginator = Paginator(photos, 30)
|
||||
|
@ -77,7 +79,6 @@ class AlbumDetail(DetailView):
|
|||
return context
|
||||
|
||||
|
||||
|
||||
class PhotosList(ListView):
|
||||
"""Shows all public photos sorted by user-selected ordering."""
|
||||
model = Photo
|
||||
|
@ -108,7 +109,7 @@ class PhotoDetail(DetailView):
|
|||
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, 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
|
||||
|
@ -124,21 +125,37 @@ class PhotoDetail(DetailView):
|
|||
"next": self.object.get_next(),
|
||||
"prev": self.object.get_prev(),
|
||||
"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
|
||||
|
||||
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
|
||||
class PhotoLike(View):
|
||||
"""Ajax like photo button."""
|
||||
|
||||
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:
|
||||
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):
|
||||
|
@ -175,6 +192,7 @@ class Search(TemplateView):
|
|||
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'))
|
||||
|
|
Loading…
Add table
Reference in a new issue