Я прохожу онлайн-курс CS50W в Гарварде и создаю веб-приложение, похожее на Twitter. Когда пользователь видит сообщение, мне нужно показать пользователю кнопку «Нравится» или «Не нравится» в зависимости от того, понравилось оно пользователю или нет. Также есть счетчик, показывающий, скольким пользователям понравился пост на данный момент. Я могу обновить счетчик, если пользователю понравилась или не понравилась публикация, но у меня проблема с кодом, отображающим или скрывающим кнопки.
Вот мой код:
модели.py
class Post(models.Model):
""" Model representing a post. """
user = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
no_of_likes = models.IntegerField(default=0)
def __str__(self):
return f"Post {self.id} by {self.user.username} on {self.timestamp}"
class Like(models.Model):
""" Model representing a like. """
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.user} likes {self.post}"
urls.py
path("", views.index, name = "index"),
path("like/<int:post_id>", views.like, name = "like"),
path("unlike/<int:post_id>", views.unlike, name = "unlike"),
view.py
def index(request):
""" Home page. """
posts = Post.objects.all().order_by('-timestamp')
paginator = Paginator(posts, 5)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
likes = Like.objects.all()
# Make a list of liked posts.
liked_posts = []
try:
for like in likes:
if like.user.id == request.user.id:
liked_posts.append(like.post.id)
except:
liked_posts = []
return render(request, "network/index.html", {
"posts": posts,
"page_obj": page_obj,
"likes": likes,
"liked_posts": liked_posts,
})
@login_required
def like(request, post_id):
post = Post.objects.get(pk=post_id)
user = User.objects.get(pk=request.user.id)
like = Like.objects.create(user=user, post=post)
like.save()
# Update no of likes.
post.no_of_likes = Like.objects.filter(post=post).count()
post.save()
return JsonResponse({"message": "successfully liked", "no_of_likes": post.no_of_likes})
@login_required
def unlike(request, post_id):
post = Post.objects.get(pk=post_id)
user = User.objects.get(pk=request.user.id)
like = Like.objects.filter(user=user, post=post)
like.delete()
# Update no of likes.
post.no_of_likes = Like.objects.filter(post=post).count()
post.save()
return JsonResponse({"message": "successfully unliked", "no_of_likes": post.no_of_likes})
index.html с Javascript
{% if post.id not in liked_posts %}
<button type = "button" class = "btn btn-primary" id = "like{{ post.id }}" onclick = "like('{{ post.id }}')">Like</button>
{% else %}
<button type = "button" class = "btn btn-primary" id = "unlike{{ post.id }}"onclick = "unlike('{{ post.id }}')">Unlike</button>
{% endif %}
function like(id) {
fetch(`/like/${id}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": "{{ csrf_token }}",
},
})
.then(response => response.json())
.then(data => {
document.querySelector(".no-of-likes").innerHTML = data.no_of_likes + " likes";
})
.then(() => {
document.getElementById("unlike" + id).style.display = "block";
document.getElementById("like" + id).style.display = "none";
});
}
function unlike(id) {
fetch(`/unlike/${id}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": "{{ csrf_token }}",
},
})
.then(response => response.json())
.then(data => {
document.querySelector(".no-of-likes").innerHTML = data.no_of_likes + " likes";
})
.then(() => {
document.getElementById("unlike" + id).style.display = "none";
document.getElementById("like" + id).style.display = "block";
});
}
Я могу обновить счетчик, не обновляя страницу, но с кнопками дело обстоит иначе. Вот что происходит:
--> Когда я нажимаю кнопку «Нравится», счетчик обновляется. Мне нужно обновить страницу, чтобы изменить кнопку на «Не похоже». Согласно спецификации это должно быть сделано асинхронно (предполагается, с помощью Javascript!), без перезагрузки страницы.
--> То же самое и с кнопкой «Не похоже». Когда я нажимаю на него, счетчик обновляется, но мне приходится перезагрузить страницу, чтобы изменить кнопку на «Нравится».
Я хочу изменить кнопки без перезагрузки страницы. Пробовал размещать блоки кода в разных местах, пробовал использовать условия «если еще», но все равно застрял здесь. Любая помощь приветствуется! Извините за беспорядочный код Javascript, новичок здесь.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Это потому, что вы отображаете только одну кнопку. Добавьте два: один вы скрываете, другой показываете:
<button type = "button" class = "btn btn-primary" id = "like{{ post.id }}" onclick = "like('{{ post.id }}')" style = "display: {% if post.id not in liked_posts %}block{% else %}none{% endif %};">Like</button>
<button type = "button" class = "btn btn-primary" id = "unlike{{ post.id }}" onclick = "unlike('{{ post.id }}')" style = "display: {% if post.id in liked_posts %}block{% else %}none{% endif %};">Unlike</button>Но я не понимаю, почему вам вообще нужно использовать две кнопки: просто используйте одну кнопку, которую вы используете как для лайка, так и для антилайка в зависимости от контекста.
Примечание. Не храните агрегаты в модели: определяйте агрегаты при необходимости: хранение агрегатов в модели усложняет обновление и синхронизацию данных. Вы можете использовать .annotate(…) [Django-doc] для генерации счетчиков, сумм и т. д. для каждого объекта, когда это необходимо.
Ваш код работает, спасибо. Хотя я пытался изменить код, как вы предложили! Я создал одну кнопку и написал функцию toggleLike(postId) для изменения .innerText на «Нравится» или «Не нравится», используя условия «если еще». Эта часть работает нормально. Но когда я обновляю страницу, на кнопках отображается только «Нравится». Я пытался изменить кнопки с помощью document.addEventListener('DOMContentLoaded', function() {// Logic here}, но безуспешно! Можете ли вы дать мне какие-либо предложения относительно того, как это исправить. Ваше здоровье!
@ srikk407: можно ли задать новый вопрос с новым состоянием представлений и шаблона?
Я не сильно изменил «views.py», только «кнопку HTML и код JavaScript». Вот ссылка на мой новый код: stackoverflow.com/questions/78456711/…
Почему бы просто не сделать одну кнопку вместо двух и одну спрятать. Здесь вы создаете только одну кнопку, поскольку шаблон отображается на стороне сервера.