Я пытаюсь создать твиттер, похожий на ленту социальных сетей, в Django ListView и добавил кнопку Ajax как в книге Django 3 By Example . Подобная функция прекрасно работает в DetailView, но я не могу заставить ее работать в ListView. При нажатии кнопки «Нравится» в DetailView ему нравятся все сообщения на странице, и они показывают 1 лайк, затем 11110 лайков, а затем экспоненциально возрастает. Переключение «нравится / не похоже» является правильным, но не уменьшает счет на 1; это просто продолжает расти. Пожалуйста, помогите!
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'})
Шаблон 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);
}
}
);
});
});