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?
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.
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.
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})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With