How to add Like/Unlike button to your Django Blog!

The Simplest way to add a Like button, that changes its state by refreshing the page

Posted by Radu-Alexandru Bulai on Tuesday, 08 Sep, 2020

In this mini-tutorial, we will add a Like/Unlike functionality to our Django Blog.
As a note, we will implement this feature while using a class-based view for our BlogPost DetailView.

Let's get started, first, in our we need to add to our BlogPost model the following fields:

class BlogPost(models.Model):
    likes = models.ManyToManyField(User, related_name='blogpost_like')

    def number_of_likes(self):
        return self.likes.count()

"likes" is a Many-to-many relationship with our User model, meaning that users (objects) can have multiple likes, and blog posts can have multiple likes. The function number_of_likes will return the number of likes of the current blog post object.

After every change in the file, we need to open our terminal and make the migrations to our database:

# CLI/Terminal
>> cd C:\Projects\...\YourDjangoAppMainFolder
>> python makemigrations
>> python migrate


Let's now make a function-based view for our Like button functionality. In your file, right before (or after) your BlogPost DetailView class, define a BlogPostLike function:

from django.shortcuts import get_object_or_404
from django.http import HttpResponseRedirect
from django.urls import reverse

def BlogPostLike(request, pk):
    post = get_object_or_404(BlogPost, id=request.POST.get('blogpost_id'))
    if post.likes.filter(

    return HttpResponseRedirect(reverse('blogpost-detail', args=[str(pk)]))

'blogpost_id' will be our button identificator in our blogpost_detail.html. Every time a logged-in user clicks the Like button, we will retrieve his id and then will check if that user already liked or not the current blogpost (more specifically: if like from user x exists, then remove like from current blogpost, else, add like from user x to current blogpost). Then we will redirect the user to the same blogpost page (like a refresh of that page). 

NOTE: Unfortunately, we cannot avoid the page refresh after every click of Like/Unlike button. In order to skip the refresh, it is needed to implement the whole functionality of Like/Unlike button inside our blogpost-detail HTML, using Ajax.js. This mini-tutorial will not focus on this type of implementation.

Now, it the same file, where we've implemented our BlogPost DetailView, we need to add to our get_context_data the following:

class BlogPostDetailView(DetailView):
    model = BlogPost
    # template_name = MainApp/BlogPost_detail.html
    # context_object_name = 'object'

    def get_context_data(self, **kwargs):
        data = super().get_context_data(**kwargs)

        likes_connected = get_object_or_404(BlogPost, id=self.kwargs['pk'])
        liked = False
        if likes_connected.likes.filter(
            liked = True
        data['number_of_likes'] = likes_connected.number_of_likes()
        data['post_is_liked'] = liked
        return data

Within our get_context_data function, we will retrieve the current blogpost primary key, and we will check if the currently logged-in user has liked or not this blog post. We will store in a local variable this statement, to send it further as a context to our HTML-based blogpost_detail. We will also retrieve the number of likes (calling the earlier written function) in order to display the number of likes directly in our HTML template.

Let's also add this new function-based view to our

from django.urls import path
from .views import (

urlpatterns = [
    path('blogpost-like/<int:pk>', views.BlogPostLike, name="blogpost_like"),


Finally, to our blogpost_detail.html let's write in the DjangoTemplateLanguage the following:

<!-- LIKES -->
{% if user.is_authenticated %}
  <form action="{% url 'blogpost_like' %}" method="POST">
	{% csrf_token %}

	{% if post_is_liked %}
	<button type="submit" name="blogpost_id" value="{{}}" class="btn btn-info">Unlike</button>
	{% else %}
	<button type="submit" name="blogpost_id" value="{{}}" class="btn btn-info">Like</button>
	{% endif %}
{% else %}
  <a class="btn btn-outline-info" href="{% url 'login' %}?next={{request.path}}">Log in to like this article!</a><br>
{% endif %}
<strong class="text-secondary">{{ number_of_likes }} Like{{ number_of_likes|pluralize }}</strong>

And we are done!



Log in to like this article!

Leave your comment!

Log in to add a comment!

  • No comments yet...