Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add user specific fields to Django REST Framework serializer

I want to add a field to a serializer that contains information specific to the user making the current request (I don't want to create a separate endpoint for this). Here is the way I did it:

The viewset:

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    filter_class = ArticleFilterSet

    def prefetch_likes(self, ids):
        self.current_user_likes = dict([(like.article_id, like.pk) for like in Like.objects.filter(user=self.request.user, article_id__in=ids)])

    def get_object(self, queryset=None):
        article = super(ArticleViewSet, self).get_object(queryset)
        self.prefetch_likes([article.pk])
        return article

    def paginate_queryset(self, queryset, page_size=None):
        page = super(ArticleViewSet, self).paginate_queryset(queryset, page_size)
        if page is None:
            return None

        ids = [article.pk for article in page.object_list]
        self.prefetch_likes(ids)

        return page

The serializer:

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article

    def to_native(self, obj):
        ret = super(ArticleSerializer, self).to_native(obj)

        if obj:
            view = self.context['view']
            ret['has_liked'] = False
            if hasattr(view, 'current_user_liked'):
                ret['has_liked'] = obj.pk in view.current_user_liked

        return ret

Is there a better place to inject the prefetching of liked articles, or a nicer way to do this in general?

like image 415
Robert Kajic Avatar asked Oct 19 '13 16:10

Robert Kajic


People also ask

How do you make a field optional in a serializer?

You could use a SerializerMethodField to either return the field value or None if the field doesn't exist, or you could not use serializers at all and simply write a view that returns the response directly. Update for REST framework 3.0 serializer. fields can be modified on an instantiated serializer.

How do I pass extra data to a serializer?

In function based views we can pass extra context to serializer with "context" parameter with a dictionary. To access the extra context data inside the serializer we can simply access it with "self. context". From example, to get "exclude_email_list" we just used code 'exclude_email_list = self.


1 Answers

you can do it with SerializerMethodField

Example :

class PostSerializer(serializers.ModelSerializer):
    fav = serializers.SerializerMethodField('likedByUser')

    def likedByUser(self, obj):
        request = self.context.get('request', None)
        if request is not None:
            try:
                liked=Favorite.objects.filter(user=request.user, post=obj.id).count()
                return liked == 1
            except Favorite.DoesNotExist:
                return False
        return "error"

    class Meta:
        model = Post

then you should call serializer from view like this:

class PostView(APIVIEW):
     def get(self,request):
         serializers = PostSerializer(PostObjects,context={'request':request})
like image 170
rapid2share Avatar answered Sep 21 '22 12:09

rapid2share