djangoajaxinstagramsocial-media-like

How to implement Like feature similar to Instagram with Django using ajax?


hi I have been making a social media site with a like feature similar to Instagram where user does not need to view the individual post to like it but can like that post directly from the main page , how can i do that ?

my main template:

{% load static %}

        {% if user.is_authenticated %}
        {% if obj %}
        <h1 style="background:skyblue;text-align:center;">Posts</h1>
            {% for obj in obj %}
            <div style="background:lightgrey;border-radius:5px;margin-bottom:20px;padding:1rem;">
                   <form method="get">
                       <input  hidden  value="{{obj.id}}" name="liked_post_id">
                   </form>

                <p>{{obj.user}}</p>
                <p>{{obj.name}}</p>
                <img height="250px" width="100%" src="{{  obj.image.url  }}" alt="Image ">
                <p>{{obj.desription}}</p>
<!--                {% include "like_page.html" %}-->
                <button id="btn_1"  name="btn_1" type="submit" value="{{ obj.id }}">like </button>
                <span id="like_count">{{obj.like_count}}</span>

                <h4>add a comment</h4>
                {% include "comments.html" %}
            </div>
            {% endfor %}

        {% else %}
        <h1 style="background:skyblue;text-align:center;">No Posts available</h1>
        {% endif %}
        {% endif %}

my urls :

from django.urls import path
from .views import index, show, LikeView, addComment\
    # , likeviewNumber


urlpatterns = [
    path("", index, name="home"),
    path("show", show, name="show"),
    path("like/", LikeView, name="post_like"),
    path("comment/",addComment, name="comment" ),
   # path('like_num',likeviewNumber )
]

the ajax I used:

 <script src="{% static 'jquery-3.6.0.js' %}" type="text/javascript"></script>
    <script>
        $(document).on('click','#btn_1',function(e){
            e.preventDefault();
          $.ajax({
            type:'POST',
            url:'{% url "post_like" %}',
            data:{
              postid:$('post_id').val(),  // idher mene abhi name=Post_id use kia ha <like_page.html> k ander  /warna yahan par buton ki id use hoti ha #btn_1
              csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val(),
              action:'post'
            },
            success:function(json){
              document.getElementById("like_count").innerHTML=json['result']
              console.log(json)
            },
            error:function(xhr,errmsg,err){
           }
         });
})



 </script>

now my main problem is that I am showing all posts in a for loop and when the like button is clicked it contains the same id in each post but contains the individual unique post.id value but the ajax thinks I am clicking the very first button even when I like the last post I need a way to like each post from the main page like users post likes in Instagram without having to make a post details page please help .

sorry forgot to put the view i have been using ::

from django.shortcuts import render, HttpResponse, get_object_or_404
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth import login
from django.urls import reverse_lazy,reverse
from .models import Posts, Comments
from django.http import HttpResponseRedirect, JsonResponse
# Create your views here.

def LikeView(request):
    if request.POST.get('action') == 'post':
            # post_id = request.POST.get('post_id')
            result = ''
            id = request.POST.get('postid')
            post = get_object_or_404(Posts, id=id)
            if request.user in post.like.all():
                post.like.remove(request.user)
                post.like_count -= 1
                result = post.like_count
                post.save()
            else:
                post.like.add(request.user)
                post.like_count += 1
                result = post.like_count
                post.save()

            return JsonResponse({'result': result})

the model :

class Posts(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    post_name = models.CharField(max_length=150)
    desription = models.CharField(max_length=200)
    image = models.ImageField(upload_to="images/uploads")
    like = models.ManyToManyField(User, related_name="liked", blank=True, default=None)
    # like_count = models.BigIntegerField(default=0)
    date_added = models.DateField(auto_now_add=True, blank=True)

    @property
    def like_count(self):
        return self.like.count()

    def __str__(self):
        return self.desription

    class Meta:
        db_table = "Posts"
        ordering = ["date_added"]

Solution

  • You should use a class to trigger the AJAX action and then you can provide the ID of your post in a data- attribute like this :

    <button class="likeBtn" data-post-id="{{ obj.id }}">like</button>
    <span id="like_count{{ obj.id }}">{{obj.like_count}}</span>
    

    And in your Javascript :

    <script>
        $('.likeBtn').on('click', function() {
            $.ajax({
                type: 'POST',
                url: '{% url "post_like" %}',
                data: {
                    postid: $(this).data('postId'),
                    csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),
                    action:'post'
                },
                success: (json) => {
                    $('#like_count' + $(this).data('postId')).html(json['result'])
                    console.log(json)
                },
                error: (xhr, errmsg, err) => {
                    console.error(xhr, errmsg, err)
                }
            })
        })
    </script>