Say I have two models like this:
from django.contrib.auth import User
class Post(models.Model):
text = models.TextField()
class Like(models.Model):
pos
I think you can use annotate() with RawSQL for this.
If that doesn't work, you can use prefetch_related with a Prefetch object, so that Django loads all the related likes with one extra query.
Post.objects.all().prefetch_related(
Prefetch('current_user_likes', queryset=Like.objects.filter(user=request.user))
)
Then as you loop through the queryset, you would do:
for post in qs:
if post.current_user_likes.all():
# do something
Note that you are using all() here, because the results have already been fetched. Normally exists() would be more efficient if you don't need the results, but here it would cause extra queries.
I ended up with a simpler approach, because I display Post objects in my views with pagination, so my Post's queryset is always quite small.
Also, I display Post objects ordered by pk.
So my solution was building a python list of Post primary keys that request.user liked, chosen from posts I'm currently displaying (so the list will always be quite small):
pks = [ post.pk for post in queryset ]
first = pks[0]
last = pks[-1]
context['liked_posts'] = Like.objects.filter(user=request.user,
post_id__range=sorted([first, last])).values_list('post_id', flat=True)
Then in my template I simply check if each Post pk is in the liked_posts list.
This approach requires only an extra query to the DB.