Reputation: 9087
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?
Upvotes: 13
Views: 10088
Reputation: 4654
According to the Django Documentation - SerializerMethodField, I had to change the code of rapid2share slightly.
class ResourceSerializer(serializers.ModelSerializer):
liked_by_user = serializers.SerializerMethodField()
def get_liked_by_user(self, obj : Resource):
request = self.context.get('request')
return request is not None and obj.likes.filter(user=request.user).exists()
Upvotes: 1
Reputation: 542
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})
Upvotes: 27
Reputation: 7386
I'd be inclined to try and put as much of this as possible on the Like
model object and then bung the rest in a custom serializer field.
In serializer fields you can access the request
via the context
parameter that they inherit from their parent serializer.
So you might do something like this:
class LikedByUserField(Field):
def to_native(self, article):
request = self.context.get('request', None)
return Like.user_likes_article(request.user, article)
The user_likes_article
class method could then encapsulate your prefetching (and caching) logic.
I hope that helps.
Upvotes: 8