Home > Mobile >  How to add field to Django queryset
How to add field to Django queryset

Time:05-05

I'm learning DRF and trying to make website, where users can leave reviews for some products and also rate (like or dislike) this reviews. So now I'm stuck in like system. For example I have these models:

class Review(models.Model):
    author = models.ForeignKey(User)
    text = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

class Reaction(models.Model):
    author = models.ForeignKey(User)
    review = models.ForeignKey(Review, related_name='reactions')
    like = models.BooleanField()  # True = like, False = dislike

And I want to show list of posts with like and dislike counters and also somehow mark that logged user already liked or disliked a post. I made view to list posts with counters, but don't know how to include information about post was rated by user.

class ListReviews(generics.ListAPIView):
    serializer_class = ProductReviewSerializer

    def get_queryset(self):
        product_slug = self.kwargs['product_slug']
        queryset = Review.objects.filter(product__slug=product_slug).annotate(
                likes_count=Count('reactions', filter=Q(reactions__like=True)),
                dislikes_count=Count('reactions', filter=Q(reactions__like=False)),
                user_reaction=...
                )
        return queryset

Is it possible at all? Or it's better to just make another endpoint to get user reactions for current page?

CodePudding user response:

This can be done using a Subquery that selects Reviews filtered by the current user and use that as an annotation

# You'll need these imports
from django.db.models import Q, Count, OuterRef, Subquery

def get_queryset(self):
    product_slug = self.kwargs['product_slug']
    user_reactions = Reaction.objects.filter(review=OuterRef('pk'), author=self.request.user)
    queryset = Review.objects.filter(product__slug=product_slug).annotate(
        likes_count=Count('reactions', filter=Q(reactions__like=True)),
        dislikes_count=Count('reactions', filter=Q(reactions__like=False)),
        user_reaction=Subquery(user_reactions.values('like')[:1])
    )
    return queryset

The user_reaction annotation will then be True, False or None when the user liked a review, disliked a review or hasn't reacted respectively

  • Related