I am attempting to make a twitter like social media feed in a Django ListView and have added an Ajax like button from the Django 3 By Example book. The like feature works perfectly in the DetailView but I cannot get it to work in the ListView. When hitting the like button in the DetailView it likes all of the posts on the page and will show 1 like, then 11110 likes, then goes up exponentially from there. The toggling of like/unlike is correct but does not reduce the count by 1; it just keeps going up. Please help!
Models.py:
class Post(models.Model):
content = models.TextField(max_length=150, blank=True)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
image = models.ImageField(storage=PrivateMediaStorage(), upload_to = pics_path, blank=True, null=True)
vid = models.FileField(storage=PrivateMediaStorage(), upload_to = vids_path, blank=True, null=True)
users_like = models.ManyToManyField(User, related_name='posts_liked', blank=True)
Views.py:
@require_POST
def post_like(request):
post_id = request.POST.get('id')
action = request.POST.get('action')
if post_id and action:
try:
post = Post.objects.get(id=post_id)
if action == 'like':
post.users_like.add(request.user)
else:
post.users_like.remove(request.user)
return JsonResponse({'status':'ok'})
except:
pass
return JsonResponse({'status':'ko'})
Template aka post_list.html:
{% with total_likes=post.users_like.count users_like=post.users_like.all %}
<div class="post-info">
<div>
<span class="count">
<span class="total">{{ total_likes }}</span>
like{{ total_likes|pluralize }}
</span>
<a href="#" data-id="{{ post.id }}" data-action="{% if request.user in users_like %}un{% endif %}like" class="like button">
{% if request.user not in users_like %}
Like
{% else %}
Unlike
{% endif %}
</a>
</div>
</div>
{% endwith %}
jQuery:
var csrftoken = Cookies.get('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$(document).ready(function(){
$('a.like').click(function(e){
e.preventDefault();
$.post('{% url "like" %}',
{
id: $(this).data('id'),
action: $(this).data('action')
},
function(data){
if (data['status'] == 'ok')
{
var previous_action = $('a.like').data('action');
// toggle data-action
$('a.like').data('action', previous_action == 'like' ? 'unlike' : 'like');
// toggle link text
$('a.like').text(previous_action == 'like' ? 'Unlike' : 'Like');
// update total likes
var previous_likes = parseInt($('span.count .total').text());
$('span.count .total').text(previous_action == 'like' ? previous_likes + 1 : previous_likes - 1);
}
}
);
});
});
2
Answers
Seems like you are selecting all
a.like
elemnents on the DOM, same forspan.count.total
You should be more specific when selecting, ideally using id. For example in the
<a>
:Then in jQuery:
Same for the span elements. Keep in mind that you should use unique id for each element, so maybe you could append suffix like
id="{{ post.id }}_like"
,id="{{ post.id }}_count"
,id="{{ post.id }}_total"
to differentiate.HTML
PYTHON