13

我想向序列化程序添加一个字段,其中包含特定于发出当前请求的用户的信息(我不想为此创建单独的端点)。这是我的做法:

视图集:

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

序列化器:

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

有没有更好的地方来注入喜欢的文章的预取,或者一般来说有更好的方法来做到这一点?

4

3 回答 3

27

你可以用SerializerMethodField

例子 :

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

那么你应该像这样从视图中调用序列化程序:

class PostView(APIVIEW):
     def get(self,request):
         serializers = PostSerializer(PostObjects,context={'request':request})
于 2014-05-14T08:07:13.940 回答
8

我倾向于尝试将尽可能多的内容放在Like模型对象上,然后将其余部分放入自定义序列化程序字段中。

在序列化器字段中,您可以request通过它们从父序列化器继承context的参数访问。

所以你可能会做这样的事情:

class LikedByUserField(Field):
    def to_native(self, article):
        request = self.context.get('request', None)
        return Like.user_likes_article(request.user, article)

然后user_likes_article该类方法可以封装您的预取(和缓存)逻辑。

我希望这会有所帮助。

于 2013-10-21T10:05:57.033 回答
1

根据Django 文档 - SerializerMethodField,我不得不稍微更改 rapid2share 的代码。

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()
于 2017-10-23T00:10:02.437 回答