[Answer]-Django (django-rest-framework) looking for a best practice to find out wether request.user exists in blog.likes

1๐Ÿ‘

โœ…

I can think of a two ways to achieve this.

  1. If you just need a boolean True/False whether the Post is liked by the request.user, you can use .extra.

    1.1. Alter your BlogPost Queryset to something like this:

    class BlogPostQuerySet(models.QuerySet):
        def annotate_is_liked_by_user(self, user):
            return self.extra(
                select = {'is_liked': 'EXISTS( \
                    SELECT `id` FROM `blogpostlikes` \
                    WHERE `blogpostlikes`.`blogpost_id` = `blogpost`.id \
                    AND `blogpostlikes`.`user_id` = %s)' % user.id
                }
            )
    
    class BlogPost
        # other stuffs here
        objects = BlogPostQuerySet.as_manager()
    

    1.2. Alter get_queryset method inside BlogPostList view

    class BlogPostList(ListAPIView):
    
        def get_queryset(self):
            user = self.request.user
            return BlogPost.objects.annotate_is_liked_by_user(user)
    

    1.3. Add the new field to the BlogPostSerializer

    class BlogPostSerializer(serializer.ModelSerializer):
        # ....
        is_liked = serializers.BooleanField(source='is_liked')
        # ...
    
  2. Get the whole BlogPostLike object.

    2.1.Alter the get_queryset method.

    class BlogPostList(ListAPIView):
    
        def get_queryset(self):
            user = self.request.user
            return BlogPost.objects.prefetch_related(
                Prefetch(
                    'likes', 
                    queryset=BlogPostLikes.objects.filter(user=user) \
                        .select_related('user'), 
                    to_attr='likes_by_request_user'
                )
            )
    

    2.2. Alter the serializer. But this can be done in two ways:

    2.2.1. Serializing a list with one item inside:

    class BlogPostSerializer(serializer.ModelSerializer):
        # ...
        likes_by_request_user = BlogPostLikesSerializer(many=True)
    

    and remove the blogpost = BlogPostSerializer() from BlogPostLikesSerializer. I think this can lead to infinite loop.

    2.2.2 Serialize a single object:

    class BlogPostSerializer(serializer.ModelSerializer):
        # ...
        like_by_request_user = BlogPostLikesSerializer(source='get_last_like', required=False)
    

    but this way you will have to add a new method inside your BlogPost object to return this single Like object

    class BlogPost(models.Model):
        #...
        def get_last_like(self):
            if hasattr(self, 'likes_by_request_user') and len(self.likes_by_request_user) > 0:
                return self.likes_by_request_user[0]
            return None
    
๐Ÿ‘คTodor

0๐Ÿ‘

You can use a SerializerMethodField to get your flag dynamically, like this:

class BlogPostSerializer(serializer.ModelSerializer):
    user = SomeUserSerializer()
    likes = BlogPostLikesSerializer()
    has_liked = SerializerMethodField("get_has_liked")
    class Meta:
        model = BlogPostLikes
        fields = ("id", "user", "likes", "content", "image", "has_liked")

    def get_has_liked(self, obj):
        user = self.context.get('request').user
        return len([l.user.id == user.id for l in obj.likes]) > 0

However, youโ€™d need to pass the request when instantiating your serializer, by doing something like this: serializer = BlogPostSerializer(context={'request': request})

๐Ÿ‘คaxelcdv

Leave a comment