Check if element is in a model - Django templates

Viewed 396

i'm trying to make a like button. And everything works fine except for the fact that i can't check (inside the template) if something is already liked by the user. In other words, i can't check for an existing row in the database.

Im trying this for the template: If the user likes the post. That post shows a filled heart, otherwise it shows only a heart contour

{% for post in posts %}
   {% if post in likelist %}
      <i class="fa fa-heart like" data-id="{{ post.id }}" id="like-{{ post.id }}" style="color:red;"></i>
   {% else %}
      <i class="fa fa-heart-o like" data-id="{{ post.id }}" id="like-{{ post.id }}" style="color:red;"> 
   </i>
   {% endif %} 
{% endfor %}

But the if statement is giving always False, even when the user actually likes the post.

Here is the model:

class Likelist(models.Model):
    user = models.ForeignKey('User', on_delete=models.CASCADE, related_name='liker')
    likes = models.ForeignKey('Posts', on_delete=models.CASCADE, related_name='likes')

    def __str__(self):
        return f"{self.user} likes {self.likes}"

And i'm passing the context in views.py through render

return render(request, "network/profile.html", {
      #[...]some other contexts
      "posts": Posts.objects.filter(user=user_id).order_by('-timestamp'), 
      "likelist": Likelist.objects.filter(user=request.user),
    })

If i try to print it in a HTML tag ( {{likelist}} or {{posts}} ) the querysets appears so the context is passing fine. I don't know why the conditional isn't checking the existence of the element in the database

1 Answers

likelist is a collection of Likelist objects, post is Post object, so a Post object can never be in likelist.

But even if it was, it is not a good idea to check membership like that, since it will make an extra query for each Post object. You can annotate the Posts and check if these are liked with an Exists subquery [Django-doc]:

from django.db.models import Exists, OuterRef

posts = Posts.objects.filter(
    user=user_id
).annotate(
    is_liked=Exists(Likedlist.objects.filter(
        likes=OuteRef('pk'), user=user_id
    ))
).order_by('-timestamp')

return render(request, 'network/profile.html', {
    'posts': posts,
})

Then in the template, you check with:

{% for post in posts %}
   {% if post.is_liked %}
      …
   {% else %}
      …
   {% endif %} 
{% endfor %}

Note: normally a Django model is given a singular name, so Post instead of Posts.

Related