在DRF中覆盖序列化器的数据属性

6 投票
1 回答
2210 浏览
提问于 2025-05-11 01:55

我正在使用django-rest-framework-mongoengine来做一个个人项目。我想在列表请求中发送一些额外的数据。为此,我写了两个混合类:

UserSearializerContextMixin:这个混合类的作用是收集列表中所有实例的用户ID。

class UserSerializerContextMixin(object):
    user_lookup_field = 'user_id'
    user_fields_required = ['id','full_name','image','level']
    _user_ids = []

    def update_context(self,user_id):
        if not self.context.get('user_ids'):
            self.context['user_ids'] = [user_id]
        else:
            self.context['user_ids'].append(user_id)

    def to_representation(self,instance):
        self.update_context(getattr(instance,self.user_lookup_field))
        return super(UserSerializerContextMixin,self).to_representation(instance)

UserSerializerDataMixin:这个混合类用来重写数据属性,使用在to_representation部分准备好的上下文。

class UserSerializerDataMixin(object):

    @property   
    def data(self):

        ret = super(UserSerializerDataMixin, self).data
        // Override the data
        return ReturnDict(ret, serializer=self)

然后在我的序列化器中,我做了类似这样的事情:

class DFSerializer(UserSerializerContextMixin,UserSerializerDataMixin,DocumentSerializer):
    //Fields and all

但是不知怎么的,代码就是没有进入我重写的数据属性。我觉得逻辑上来说,数据属性应该通过扩展混合类来被重写。但在这里并没有发生这种情况。

可能是什么原因呢?该怎么解决呢?

相关文章:

  • 暂无相关问题
暂无标签

1 个回答

1

这是一个非常老的问题,但如果有人碰巧看到这个,还是想分享一下:

我来这里是因为我对drf(Django REST框架)在使用TemplateHTMLRenderer时,要求的序列化输出和其他渲染器不一样感到不满意。所以其中一个可能的解决办法是重写data属性,让它返回一个包含序列化器和数据的字典,而不是返回一个包含相同序列化器和数据的ReturnList

不过,这里有个问题,就是在ViewSet中列出记录时,使用的不是你直接实例化的序列化器,而是一个叫做ListSerializer的东西。这个ListSerializer会为每一条需要序列化的记录调用你的序列化器。

一个看起来不太优雅的“修复”这个问题的方法可以这样做:

class YourViewSet(SomeBaseViewSet):

....

def get_serializer(self, *args, **kwargs):

    res = super().get_serializer(*args, **kwargs)

    class Patch(res.__class__):

        @property
        def data(self):
            request = self.context['request']
            if isinstance(request.accepted_renderer, TemplateHTMLRenderer):
                return dict(data=super().data,
                            serializer=self.child if isinstance(self, serializers.ListSerializer) else self)
            return super().data

    res.__class__ = Patch

    return res

截至我写这段话的时候,我还在考虑解决我这个特定问题(TemplateHTMLRenderer需要不同的序列化输出)的最佳方法。我接下来会测试重写渲染器,但上面的做法对我来说已经“解决”了我的问题,也解释了为什么代码没有按照提问者的预期工作。

撰写回答