Home > other >  How to check if an object is in another queryset
How to check if an object is in another queryset

Time:07-04

I need to check if a user has liked a post on a page that displays all posts, I am passing the posts and user's likes below

def index(request):
if request.method == "POST":
    text = request.POST["post-text"]
    Post.objects.create(
        entity = Entity.objects.create(
            user = request.user,
            text = text
        )
    )
    return HttpResponseRedirect(reverse("index"))

return render(request, "network/index.html", {
    "posts" : Post.objects.all().order_by('-entity__date', '-entity__id'),
    "likes" : Like.objects.filter(user = request.user)
})

this is the model

class Entity(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="posts")
    text = models.TextField()
    date = models.DateTimeField(default=datetime.now())

class Like(models.Model):
    entity = models.ForeignKey(Entity, on_delete=models.CASCADE, related_name="likes")
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="likes")

class Post(models.Model):
    entity = models.ForeignKey(Entity, on_delete=models.CASCADE, related_name="post")

Template:

{% for post in posts %}
<div>
  <div>{{post.entity.user}}</div>
  <div>{{post.entity.text}}</div>
  <div>{{post.entity.date}}</div>
  <div  data-id="{{post.entity.id}}">
    {% if post.entity in likes %}
    <p>yes</p>
    {%else%}
    <p>no</p>
    {%endif%}

    <div >{{post.entity.likes.count}}</div>
  </div>
  <br />
  <a href="#">Comment</a>
  <hr />
</div>
{% endfor %}

I don't know how to write the if condition, I've tried this {% if post.entity in likes %} but it doesn't work.

CodePudding user response:

Please don't. While this can be done with such condition, it would result in a lot of extra queries. You can work with a Exists subquery [Django-doc]:

from django.contrib.auth.decorators import login_required
from django.db.models import Exists, OuterRef
from django.shortcuts import redirect

@login_required
def index(request):
    if request.method == 'POST':
        text = request.POST['post-text']
        Post.objects.create(
            entity = Entity.objects.create(
                user = request.user,
                text = text
            )
        )
        return redirect('index')
    posts = Post.objects.annotate(
        is_liked=Exists(
            Like.objects.filter(user=request.user, entity_id=OuterRef('entity_id')
        )
    ).select_related('entity').order_by('-entity__date', '-entity__id')
    
    return render(request, "network/index.html", {
        'posts' : posts
    })

The Post objects will then have an extra attribute .is_liked that is True if that Post is liked by the logged in user.


Note: You can limit views to a view to authenticated users with the @login_required decorator [Django-doc].


Note: You can make use of redirect(…) [Django-doc] instead of first calling reverse(…) [Django] and then wrap it in a HttpResponseRedirect object [Django-doc]. The redirect(…) function does not only offer a more convenient signature to do this, it also for example will use the .get_absolute_url() method [Django-doc] if you pass it a model object.


Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.


Note: Django's DateTimeField [Django-doc] has a auto_now_add=… parameter [Django-doc] to work with timestamps. This will automatically assign the current datetime when creating the object, and mark it as non-editable (editable=False), such that it does not appear in ModelForms by default.

CodePudding user response:

I think it is easier to perform the logic of sorting the Entities/Likes/User inside the view and then pass the correctly formatted data to the template.

This is good practice because soon enough you will want to perform more difficult transformations with the data which will be very hard if not impossible inside the django template. That is also why this kind of logic belongs inside the view.

  • Related