Reputation: 89
I am currently working on building a "like" system for a blog-style website in Django. I've been looking at several different examples for setting up the HTML templates and was hoping to better understand some of the logic.
My first thought was to tie the "like" button to the corresponding view like so:
<a class="btn btn-secondary" href="{% url 'post-like' post.id %}" role="button">Like ({{ post.likes.count }})</a>
This seemed to work decently well (the "like" was registering and showing up in the count) but I was having trouble getting back to the right page after clicking the "like" button (i.e. when I clicked "like" it took me to some other page vs. staying on the home page).
I then found another example online that created a get_like_url()
function under the broader Post
Model
like this:
def get_like_url(self):
return reverse("post-like", kwargs={"pk":self.id})
And then called it in the template like this:
<a class="btn btn-secondary" href="{{ instance.get_like_url }}" role="button">Like ({{ post.likes.count }})</a>
I thought this was basically doing the same thing but when I used this method it would return me to the home page of my site but wouldn't register the like (i.e. didn't seem like the button actually did anything).
Could anyone help me understand what is going on here?
For reference, here is my View
for the "like" system:
class LikeView(View):
model = Post
context_object_name = 'posts'
def get(self, request, pk=None):
user = self.request.user
post = Post.objects.get(pk=pk)
updated = False
liked = False
if user.is_authenticated:
if user in post.likes.all():
liked = False
post.likes.remove(user)
else:
liked = True
post.likes.add(user)
updated = True
data = {
"updated": updated,
"liked": liked,
}
return HttpResponse(data)
And my URL pattern
:
path('post/like/<int:pk>', LikeView.as_view(), name='post-like')
Thanks in advance for the help!
Upvotes: 3
Views: 4346
Reputation: 31
I implemented it as a model, I'm not sure this is the best way to do it, but it worked for me.
class Like(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="likes")
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE,
related_name="likes")
created = models.DateTimeField(auto_now_add=True)
class Meta:
constraints = [
models.UniqueConstraint(fields=['user', 'post'], name="unique_like"),
]
I also used the unique like per user in the model using UniqueConstraint. You can also use genericForeignKey for liking comments, notes, etc.
@method_decorator(login_required, name='dispatch')
class LikeView(View):
def get_success_url(self):
return reverse("posts:detail", kwargs={"pk": self.kwargs.get("pk")})
def get(self, request, *args, **kwargs):
like = Like()
like.post = get_object_or_404(Post, pk=self.kwargs.get("pk"))
like.user = self.request.user
like.save()
return redirect(self.get_success_url())
In the template:
{% if request.user.pk not in post.get_likes_users %}
<a href="{% url 'posts:like' pk=post.pk %}">
<i class="fa fa-thumbs-up"></i>
Like
</a>
{% else %}
/* dislike implementation*/
{% endif %}
Upvotes: 3