在django rest serializer中修改相关模型上的字段

时间:2017-06-22 20:52:51

标签: django serialization django-models django-views django-rest-framework

我尝试使用this answer中的方法扩展用户模型。

我的想法是只在每次向api发出关于用户的请求时发送配置文件对象。

我完成了以下工作:

# views.py
class ProfileDetail(APIView):
    """
    Retrieve or update a profile instance.
    """
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, )
    ...
    def get(self, request, pk, format=None):
        ...

    # Only allow owners to update a profile
    def put(self, request, pk, format=None):
        profile = self.get_object(pk)
        if request.user != profile.user:
            raise PermissionDenied
        serializer = OwnerProfileSerializer(
            profile,
            data=request.data,
            context={"request": request},
        )
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

我的序列化器看起来像这样:

#serializers.py
# Serializer for the owner of profile object
class OwnerProfileSerializer(serializers.HyperlinkedModelSerializer):
    user = serializers.ReadOnlyField(source='user.id')
    first_name = serializers.ReadOnlyField(source='user.first_name')
    last_name = serializers.ReadOnlyField(source='user.last_name')
    email = serializers.(source='user.email')

    class Meta:
        model = Profile
        fields = (
            'url',
            'id',
            'dob',
            'bio',
            'town',
            'gender',
            'image',
            'user',
            'first_name',
            'last_name',
            'email',
        )

我希望所有者也能够修改user个对象字段,例如first_namelast_nameemail等。

但是我没有在DRF序列化程序文档中找到(例如)ReadWriteField

我怎么能做到这一点?如果可能,我希望通过Profile视图/序列化程序而不是用户执行所有修改。

- 编辑 -

作为测试,我将ReadOnlyField替换为last_name = serializers.CharField(source='user.last_name')。当我尝试更新它时,DRF给了我这个错误:

  

.update()方法不支持可写的点源字段   默认情况下。为序列化器编写明确的.update()方法   profiles.serializers.OwnerProfileSerializer,或设置read_only=True   在点源序列化器字段上。

所以看起来我可以实现自己的update方法。但我不确定如何继续。

2 个答案:

答案 0 :(得分:1)

我设法通过在序列化程序上扩展update方法来修复它:

class OwnerProfileSerializer(serializers.HyperlinkedModelSerializer):

    user = serializers.ReadOnlyField(source='user.id')
    first_name = serializers.CharField(source='user.first_name')
    last_name = serializers.CharField(source='user.last_name')
    email = serializers.ReadOnlyField(source='user.email')

    def update(self, instance, validated_data):

        user = instance.user
        # pprint(vars(user))
        print(validated_data)
        for updated_field in validated_data['user']:
            value = validated_data['user'][updated_field]
            setattr(user, updated_field, value)

        for updated_field in validated_data:
            if updated_field == 'user':
                for user_field in validated_data['user']:
                    value = validated_data['user'][user_field]
                    setattr(user, user_field, value)
            else:
                value = validated_data[updated_field]
                setattr(instance, updated_field, value)

        user.save()
        instance.save()
        return instance

    class Meta:
        model = Profile
        fields = (
            'url',
            'id',
            ....

但是,当我需要验证电子邮件地址更改时,这可能会在以后遇到问题。在这种情况下,根据@ Kostas'编写用户序列号。建议可能有用

答案 1 :(得分:-1)

一种选择是在您的应用中加入UserSerializer,并使其可编辑。例如,这应该是这样的:

class OwnerProfileSerializer(serializers.HyperlinkedModelSerializer):
    user = CustomUserSerializer(read_only=False).

这也会影响api响应的结构,但我相信这可以适用于你的情况。