How to Add Like and Dislike Buttons to a Post with Python in Django
In this article, we show how to add like and dislike buttons to a post with Python in Django.
This gives a user the ability to like or dislike a post, just as you can see on many sites all over the web, such as youtube (with videos), comments (such as on facebook), and so on.
We can then keep track of the posts that each user on the site has liked or disliked.
Now in order to create this, it's a relatively massive thing.
We need a number of databases.
We need a relatively in-detail views.py code for our function.
So, when thinking about how to implement this, it creates a good amount of thought.
What type of database tables do we need to store these likes or dislikes?
So the best thing I thought of was to create a table. I call it Preference (for the user's preference of like or dislike). This table is really a Big Like table for all the likes or and dislikes of users. It's going to be composed of 3 different fields. The fields are going to user, post, and value.
user and post are going to be ForeignKeys. This means they are taken from another database table, which are Django's built-in user class and our Post model (the model I created for posts of the site). We use ForeignKeys because we want to link the posts definitively to each object. Always use ForeignKeys if you want to link an object on your site (in this case, a like or dislike to a post), because each object contains its own unique identifier (which is the primary key).
The third field is going to be the value. If the user likes the post, we're going to give it a value of 1. If the user dislikes the post, we're going to input in a value of 2. So 1=like, 2=dislike
In order to be able to do add like/dislike functionality and visualize the whole process, below is the Post model, because we use the post model to store the likes and dislikes for each particular post.
This is the Post model that I use.
So this post has fields, title, url, content, pub_date, last_edited, author, likes, and dislikes.
The only two that interests us for this project is likes and dislikes. These are both integer fields, which both have a default value of 0. This because when the post is initially created, no one has liked or disliked it yet.
So keep in mind that we have a Post model that has 2 fields, likes and dislikes, for keeping track of likes and dislikes of the post.
Likes/Dislikes Model
So previously, we showed the Post model, which is the post that can be liked or disliked.
Next, we need another model. We need the model which keeps track of which users have liked or disliked a post. We need this model because we don't want a user to be able to like or dislike a post more than one time. Therefore, we can keep track of which users have liked or disliked a post. If a user has liked or disliked a post, s/he cannot like or dislike that post again.
So I decided to call this model, Preference.
This is because it's the user's preference.
And, as explained above, it has 3 fields, user, post, and value. user and post are ForeignKey fields, meaning they are linked to other databases.
This Preference model is shown below.
So we create a model named Preference.
The first field, user, is a ForeignKey from Django's built-in User model.
The second field, post, is a ForeignKey from the Post model we created.
The third field, value, is an IntegerField, which will hold the value of the like. 1= like. 2=dislike.
The fourth field, just to have more meta data, is the date field, to know when the user liked or disliked the post.
Just to make likes or dislikes more readable in the Django admin, I use the __str__ function to show the user, post, and value, instead of just Preference objects.
Since the user, post, and value have to be unique (we don't want duplicates of likes for the same post by the same user), we make the 3 fields
unique together.
urls.py File
Next we will go over the urls.py file.
Based on the URL that gets submitted to the web browser determines which function will be executed.
We set up this URL in our urls.py file, so that if, postid/preference/userpreference/, is entered, where postid is the id of the post and userpreference is either 1 for like or 2 for dislike, it executes the postpreference function in the views.py file.
Below is the content of our urls.py file.
The last url is the one that is specific to liking or disliking a post.
When a user likes or dislikes a post, the postpreference function in the views.py file is executed.
Template File
Next, I'm going to go into the template file, where we have the code that allows a user to like or dislike a post.
This is the detail page of a post on the website. So this code will appear on the detail page for a post.
The code is shown below.
So on this page, we have our posts.
This is the detail page of every post on the site.
For each post, there is a title, the content, and the author.
Below is is where we put our like button, which in this case, is just a link. If you want, you can code it as a button, but in our code, we just leave it as a link.
We create an anchor tag and set the href to "#" and give it an onClick event handler. The onClick event handler will get the element on the DOM with an id of like button. When it finds this element with this id, it will then submit it. The whole point of this is for a POST request to occur. We want the like or dislike to be triggered with a POST request, not a GET request, because some web browsers pre-fetch GET requests automatically, which means, with a GET request, some likes or dislikes may happen unintentionally. To avoid this, we do POST requests. So, with this anchor tag, with a click, the form with an id of like button is executed, which means we are brought to the URL, "/posts/{{eachpost.id}}/preference/1", which is the URL that appears in the urls.py page in order to execute the postpreference function in the views.py page.
Next to the anchor tag for, Like This Post, we put the number of likes, just like youtube does.
We do the same exact thing for the dislikes. We create an anchor tag with an onClick event handler, and
tell it that when a user clicks this anchor tag to go to the element with an id of dislikebutton and submit it.
This time, we have a slightly different URL. Instead of 1 in the URL, we have 2. Remember, we make it so that 1=like and
2=dislike. This is why it's different. And this is how we are able to tell whether the user likes the post or dislikes
the post.
views.py File
Next we will go over the views.py file.
The views.py file is where we write the functional code to have likes and dislikes execute the way we want it.
Below is the code for the views.py file.
We must import render, get_object_or_404, login_required, as well as the models, Post and Preference.
We want the like and dislike buttons to be only be able to register if the user is logged in. So we add a login_required decorator to the postpreference function.
The postpreference function gets 3 parameters, request, postid, and userpreference.
Every function gets the request parameter, but we also need the postid (to know which post it is that the user has liked or disliked) and the userpreference (which is either 1 for like or 2 for dislike)>
Inside of this postpreference function, we have the if statement, if request.method == "POST", to check if the request method is POST.
We then get the specific post and save it in the variable, eachpost. We get this with the line, eachpost= get_object_or_404(Post, id=postid)
We then do a try statement.
The whole point of the try statement is we want to see whether the user has liked or disliked this post already. If the user has, we see which button the user has entered. If the user liked the post and now clicks the dislike button, we want to update the Preference and Post database tables to show that the user now dislikes the post. If the user liked the post and now clicks the like button again, we want to unlike the post for the user. The same thing is the case for the dislike button. If the user has disliked the post and now likes the post, we want to do all necessary changes within the database tables. If the user has disliked the post and now clicks the dislike button, we want to un-dislike the post.
So using the try statement, we query the Preference database table to see if the user has liked or disliked the post. From the first two fields we see whether the username and the post in mention are in the database. If they are, the next step is to get the number from the value field, which can either be 1 for a like or 2 for a dislike. We get the value and store it in the variable, valueobj. We make sure that this variable is an int, so we type cast it with the int() function.
Then we do an if statement that if the value in the Preference database (for the value column) is not equal to userpreference (1=like, 2=dislike), then we have to change around the values.
The easiest way I found to do this was to delete the object from the Preference database and start over.
So after the deletion of the object, we then create a variable, upref, and set it equal to the Preference database with the line, upref= Preference()
We set the user row of Preferene to the current logged in user, request.user
We set the post row of Preference to the current post (which is derived from the URL)
We set the value row of Preference to the userpreference (which is derived from the URL).
If userpresence is 1 and valueobj is not equal to 1, then we have to increase the likes by 1 and decrease the dislikes by 1. If userpreference is 2 and valueobj is not equal to 2, then we increase dislikes by 1 and decrease likes by 1.
We then have to make sure we have the new rows of the Preference and Post databases, which is done with the save() function.
We then have our context dictionary and we have to return our view, which is the detail page.
We then have our elif statement.
If valueobj equals the userpreference, this means that the user has liked the post and is clicking the Like the Post button or the user has disliked the post and is clicking the Dislike the Post button. If this happens, we want to unlike what the user has done, just like youtube. If you click the like button (thumbs up) on youtube and then click it again, it unlikes the post. This is what we do in this case.
So if this is case, the object is deleted.
If userpreference is equal to 1, then we subtract 1 from the likes column in the Post model.
If userpreference is equal to 2, then we subtract 1 from the dislikes column in the Post model.
We then have to make sure that we save the row in the Post model.
We then have our regular context dictionary and render the template.
Now we go to the exception.
If there is no user and post in the Preference model, meaning the user hasn't liked or disliked the post, then we have to add the user, the post, and the value to the Preference model.
We do this again by creating a variable, in this case, upref, and setting it equal to the Preference model.
We set user to the current logged in user, which is request.cuser
We set the post equal to the current post
And we set the value to userpreference.
To make userpreference an integer, we typecast it with the int() function, so that we can simply check if it's equal to a certain integer.
If userpreference is equal to 1, then we increase the total of the likes by 1. If userpreference is equal to 2, then we increase the number of dislikes by 1.
We then have to save the rows of the Preference and Post models.
We then have our context dictionary and return the detail page template.
If the request is not equal to POST, such as would be the case if we are redirecting from the login page, in case the user wasn't logged in, then we simply return the detail page.
So it was a quite a bit to do, but this is one way of adding like and dislike buttons to a post with Python in Django.
Related Resources
How to Randomly Select From or Shuffle a List in Python