Django REST框架基于上下文呈现字段(或不呈现)

时间:2018-02-08 17:49:03

标签: django django-rest-framework

我有一个汽车课

class Car(serializers.ModelSerializer):
    engine = EngineSerializer(many=False, required=False)
    owner = UserSerializer(many=False, required=False)

现在我想隐藏除了所有者以外的用户的引擎(应该在self.context['user'] == self.owner进行检查。

我可以通过将引擎变成SerializerMethodField()

来实现这一目标
class Car(serializers.ModelSerializer):
    engine = serializers.SerializerMethodField()
    owner = UserSerializer(many=False, required=False)
    def get_engine(self, obj):
        if self.context['user'] == self.owner:
            return EngineSerializer(self.engine, many=False).data
        else:
            return None or so

但这会在创建+更新时产生问题。这是什么最好的做法?我不瞄准隐私,但只是想避免序列化引擎的成本(想象它需要很长时间才能序列化,对于除了拥有者以外的人来说它是无用的)

2 个答案:

答案 0 :(得分:0)

在我看来,您可以使用自定义字段来处理此问题。

class EngineField(serializers.Field):
    def to_representation(self, obj):
        if self.context.get('user', None) == obj.owner:
            return EngineSerializer(obj.engine, many=False).data
        else:
            return None or so

    def to_internal_value(self, data):
        do_something()


class Car(serializers.ModelSerializer):
    engine = EngineField()
    owner = UserSerializer(many=False, required=False)

答案 1 :(得分:0)

Django Rest Framework很容易扩展,只需看看内部:)

例如,如果您使用的是内部使用RetrieveModelMixin的任何类型的视图/视图集, 检查RetrieveModelMixin.retrieve()方法。 它调用GenericAPIView.get_serializer()方法,将对象实例作为参数传递。

您可以覆盖该方法并根据instance.owner字段返回不同的序列化程序对象。

在视图中更改此方法后,此行为将适用于对单个对象进行操作的任何mixin。

对于queryset,它会有点棘手,但我认为如果序列化一个引擎代价很高,你可能会在返回汽车列表时完全避免序列化这个字段。

示例代码(未经过测试,肯定不是完美的,但您会明白这一点):

class CarView(rest_framework.generics.RetrieveUpdateDestroyAPIView):


    def get_serializer(self, *args, **kwargs):
        # instance returned by self.get_object is passed as first arg
        # in mixins used by RetrieveUpdateDestroyAPIView
        car = args[0]

        if self.request.user == car.owner:
            serializer_class = ComplexCarSerializerWithEngineField
        else:
            serializer_class = SimpleCarSerializerWithNoEngineField

        kwargs['context'] = self.get_serializer_context()
        return serializer_class(*args, **kwargs)


    def get_object(self):
        ...