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.