Annotate queryset with information if a particular foreign key exists

前端 未结 2 496
余生分开走
余生分开走 2021-01-03 16:24

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         


        
相关标签:
2条回答
  • 2021-01-03 16:59

    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.

    0 讨论(0)
  • 2021-01-03 17:08

    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.

    0 讨论(0)
提交回复
热议问题