tudor opran
tudor opran

Reputation: 27

How to create a like functionality in django for a blog

I have to build a blog for my chess club and I would like to make a like functionality for the posts. When the user likes the post the like count increases and the post its shown in the user profile.

Here is what I made so far:

This is my post model:

class Post(models.Model):
    title = models.CharField(max_length=100)
    overview = models.TextField()
    timestamp = models.DateTimeField(auto_now_add=True)
    content = HTMLField()
    is_aproved = models.BooleanField(default=False)
    # comment_count = models.IntegerField(default = 0)
    # view_count = models.IntegerField(default = 0)
    slug = models.SlugField(unique=True, blank=True)
    likes = models.ManyToManyField(
        settings.AUTH_USER_MODEL, blank=True, related_name='post_likes')
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    thumbnail = models.ImageField()
    categories = models.ManyToManyField(Category)
    featured = models.BooleanField()
    previous_post = models.ForeignKey(
        'self', related_name='previous', on_delete=models.SET_NULL, blank=True, null=True)
    next_post = models.ForeignKey(
        'self', related_name='next', on_delete=models.SET_NULL, blank=True, null=True)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('post-detail', kwargs={
            'id': self.id
        })

    def get_update_url(self):
        return reverse('post-update', kwargs={
            'id': self.id
        })

    def get_delete_url(self):
        return reverse('post-delete', kwargs={
            'id': self.id
        })

    @property
    def get_comments(self):
        return self.comments.all().order_by('-timestamp')

    @property
    def comment_count(self):
        return Comment.objects.filter(post=self).count()

    @property
    def view_count(self):
        return PostView.objects.filter(post=self).count()

And this is my view:

def post(request, id):
    category_count = get_category_count()
    most_recent = Post.objects.order_by('-timestamp')[:3]
    post = get_object_or_404(Post, id=id)

    if request.user.is_authenticated:
        PostView.objects.get_or_create(user=request.user, post=post)

    form = CommentForm(request.POST or None)
    if request.method == "POST":
        if form.is_valid():
            form.instance.user = request.user
            form.instance.post = post
            form.save()
            return redirect(reverse("post-detail", kwargs={
                'id': post.pk
            }))
    context = {
        'form': form,
        'post': post,
        'most_recent': most_recent,
        'category_count': category_count,
        'form': form
    }
    return render(request, 'post.html', context)

could you help me to implement this like functionality

Upvotes: 0

Views: 2756

Answers (1)

Siva Sankar
Siva Sankar

Reputation: 1830

You need another model to get liking functionality in Django. Create a like model like this-

class PostLikes(models.Model):
    user = models.ForeignKey(User)
    post = models.ForeignKey(Post)
    created = models.DateTimeField(auto_now_add=True)

then create a view to add the instance to the PostLikes model-

def like_others_post(request, post_id):
    new_like, created = PostLikes.objects.get_or_create(user=request.user, 
                                                   post_id=post_id)
    if not created:
        # you may get and delete the object as the user may already liked this 
        post before

We are using get or create to avoid duplication of likes. So a user may click multiple times but, a like instance is stored only once.

then add a method to Post model for getting the number of likes-

def Post(models.Model):
    ...
    ...
    @property
    def view_count(self):
        return PostLikes.objects.filter(post=self).count()

To find out if the current user already likes the displayed post or not, in your post view-

def post(request, id):
    ....
    ....
    already_liked = PostLikes.objects.filter(user=request.user, post=post).count()
    if number_of_likes > 0:
        already_liked = True # pass this variable to your context
    else:
        already_liked = False # you can make this anything other than boolean

Then by use of Javascript and {{already_liked}}, change your animation of like button in your template.

Upvotes: 4

Related Questions