Search code examples
djangodjango-modelsdjango-viewsdjango-querysetdjango-managers

Django Queryset dynamic field value based on request.user


I have a webservice that returns list of links.

{
     [
         {"id":1,"href":"http://website.com","title":"Title1"},
         {"id":2,"href":"http://website.com","title":"Title2"},
         {"id":3,"href":"http://website.com","title":"Title1"}
     ]
}

Now I want to extend it to return also field voted, which will tell me if user has already voted for this link or not.

{
     [
         {"id":1,"href":"http://website.com","title":"Title1","voted": "True"},
         {"id":2,"href":"http://website.com","title":"Title2","voted": "False"},
         {"id":3,"href":"http://website.com","title":"Title1","voted": "True"},
     ]
}

What is the best way to achive that?

I've created model method voted(self), but I don't think this is the best place for doing that, and still I don't have access to request.user in my model class.

 links\model.py ----------------------------------------

class Link(models.Model):
    href = models.URLField()
    title = models.CharField(max_length=400)

def voted(self, request):
    vote = UserVotes.objects.get(link_id=self.link.id, user_id=request.user)
    if vote == 1:
        return True
    else:
        return False

--------------------------------------------------------

 votes\model.py ----------------------------------------

class UserVotes(models.Model):
    user = models.ForeignKey(Account, blank=False)
    link = models.ForeignKey(Link, blank=False)
    vote = models.FloatField(null=True, blank=False)

    class Meta(object):
        unique_together = ('user', 'link')

--------------------------------------------------------

 link\serializers.py -----------------------------------

class LinkSerializer(serializers.ModelSerializer):
    voted = serializers.BooleanField()

    class Meta:
        model = Link

        fields = ('id', 'href', 'title','voted')
        read_only_fields = ('id', 'href', 'title', 'voted')

--------------------------------------------------------

Solution

  • You can add a read-only 'voted' SerializerMethodField to your serializer.

    This will add a key voted to the serialized representation of the object.

    From the SerializerMethodField docs:

    It can be used to add any sort of data to the serialized representation of your object.

    It should return whatever you want to be included in the serialized representation of the object.

    class LinkSerializer(serializers.ModelSerializer):
        voted = serializers.SerializerMethodField(method_name='has_user_voted') # add a 'voted' field
    
        class Meta:
            model = Link
    
            fields = ('id', 'href', 'title','voted')
            read_only_fields = ('id', 'href', 'title', 'voted')
    
        def has_user_voted(self, obj):
            user = self.context['request'].user # get the request object from context
            user_votes = UserVotes.objects.filter(user=user, link=obj)
            if user_votes:
                return True # return True if any user_votes object exists
            return False # otherwise return False