Reputation: 1567
I am working on a website made in Django and i want to implement a facebook type (or any social media type) like
button. I have a user
table, and a post
table, and i want users to be able to like the posts. I am confused about some particular things :
My current approach is:
post
table, say post_likes
, which have list of users who currently like the post. Then, before rendering the 'post' template, i have to loop over all the users (in field post_likes
) to check if the request.user
likes the post or not (in views.py), and send that data to template (to change the ui of like
button to liked
), but this approach seems very naive to me, also slow. What could be the better approaches? Upvotes: 1
Views: 1270
Reputation: 477170
We can do this by creating two models: Post
(that will in reality contain extra data like the message
, author
, etc.), and Like
that is acts as a many-to-many relation between a Post
and a User
:
class Post(models.Model):
total_likes = models.IntegerField(default=0)
likes = models.ManyToManyField(User, through='app.Like')
def like(self, user):
_, created = Like.objects.get_or_create(user=user, post=self)
if created:
self.total_likes += 1
self.save()
@classmethod
def update_likes(cls):
cls.objects.annotate(total=Count('likes')).update(total_likes=F('total'))
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
So the like(..)
function is used to like a post (with as parameter the user). We can thus call somepost.like(someuser)
. It will fetch or create a new Like
object that maps to the specific post
and the specific user
. In case the Like
instance already existed, nothing happend, otherwise we increment the total_likes
field that stores the total number of likes.
Perhaps you do not want to update this counter every time a user likes a post: after all, it creates some extra load on the server. In that case, the if created:
part can be omitted, and we regularly should call Post.update_likes
. This function will perform an aggregate per Post
that counts the number of likes, and it will update the total_likes
field.
Regardless whether you update total_likes
constantly, it is better to every now and then update the total number of likes per post. Since other views, models, etc. can - given you the developers are not looking very strict to this - remove Like
objects. Furthermore User
s can be removed, etc. and we have not much control about that. Yes we can create signals that are triggered after Like
s and User
s are removed (and created), but still there can be problems with counting the number of likes like race conditions. Therefore I would advice to periodically update the number of likes.
Upvotes: 2