I’m working on a web app where a user has the option to like or unlike a post posted by another user. I created a button and wrote a Javascript function to change the text inside the button based on user’s choice. If user clicks Like button it changes to Unlike and vice versa.
Here’s my code:
models.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"),
views.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()
# List of post ids.
liked_posts = Like.objects.filter(user=request.user).values_list('post', flat=True)
liked_posts = list(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()
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()
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 with Javascript
<!--Create button-->
<button type="button" class="btn btn-success like" id="like{{ post.id }}" onclick="toggleLike('{{ post.id }}')">Like</button>
// JavaScript
function toggleLike(postId) {
var likeButton = document.getElementById('like' + postId);
if (likeButton.innerText === 'Like') {
// Change button to Unlike
likeButton.innerText = 'Unlike';
likeButton.style.background = '#dc3545'; // Change button color to red
// Update counter
fetch(`/like/${postId}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": "{{ csrf_token }}",
},
})
.then(response => response.json())
.then(data => {
document.querySelector("#no-of-likes" + postId ).innerHTML = data.no_of_likes + " likes";
})
} else {
// Change button to Like
likeButton.innerText = 'Like';
likeButton.style.background = ''; // Reset button color
// Update counter
fetch(`/unlike/${postId}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": "{{ csrf_token }}",
},
})
.then(response => response.json())
.then(data => {
document.querySelector("#no-of-likes" + postId).innerHTML = data.no_of_likes + " likes";
})
}
}
When I refresh the page all buttons are changing to Like even though user liked some posts where it should display Unlike buttons.
I tried to fix this by writing following code but it didn’t resolve the issue.
document.addEventListener('DOMContentLoaded', function() {
const buttons = document.querySelectorAll(".like");
buttons.forEach(button => {
const postId = button.getAttribute('id').replace('like', '');
if ('{{ liked_posts }}'.includes(postId)) {
button.innerText = "Unlike";
button.style.background = "red";
} else {
button.innerText = "Like";
button.style.background = "green";
}
});
})
With this new code I’m getting a weird bug where if I liked only Post No. 12 by one other user, Post Nos. 1 and 2 by this same other user are also showing Unlike buttons. And if I like Post No. 11 by this other user, Post No. 1 also displaying Unlike button. I think this is something to do with .include()
function but I can’t figure out the issue. Any suggestions on how to fix this bug? Thanks in advance!