首页 > 解决方案 > 使用 RetrieveUpdateAPIView 更新数据 - 从序列化程序获取经过验证的数据

问题描述

我想通过 PUT 请求更新用户的某些属性(比如 first_name 和 last_name)我的 json 对象看起来像这样

   {
"user" :    {   
             "first_name": "Jack",   
             "last_name": "shnider",
             "password":"admin123" 
             "email" : "foo@google.com"
             },

"employee_zip" : 12345
}

这就是我的视图(我想将现有字段更新为这些新字段)。

这些是序列化程序

  class Serializer_UpdateUser(ModelSerializer):
    class Meta:
        model = User
        fields = ('first_name','last_name','password')

class Serializer_UpdateEmployer(ModelSerializer):
    user = Serializer_UpdateUser()
    class Meta:
        model = modelEmployer
        fields = [
            'user',
            'employer_zip',
        ]

这是视图:

class UpdateProfile_RetrieveUpdateAPIView(RetrieveUpdateAPIView):
    queryset = modelEmployer.objects.all()
    serializer_class = Serializer_UpdateEmployer
    lookup_field = 'user__email'
    permission_classes = [permissions.AllowAny]

    def update(self, request, *args, **kwargs):
        instance = self.get_object() #------>I have the object that I would like to update
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True) #--->Success

现在我想获得一个经过验证的字段(json 只包含已更新的字段)。我知道如果我做这样的事情

serializer.save

我会取回一个 modelEmployer 但我取回了这个错误

AssertionError at /api/employer/update_profile/employerA@gmail.com/ The `.update()` method does not support writable nested fields by default. Write an explicit `.update()` method for serializer `Employer.api.serializers.Serializer_ListEmployer`, or set `read_only=True` on nested serializer fields. Request Method: 

我有两个问题

1-为什么保存失败?

2-如何从上述序列化程序中获取经过验证的数据?

标签: djangodjango-rest-framework

解决方案


The save is failing because django-rest-framework doesn't deal with nested serializers by default.

from the django-rest-framework docs:

By default nested serializers are read-only. If you want to support write-operations to a nested serializer field you'll need to create create() and/or update() methods in order to explicitly specify how the child relationships should be saved.

You have to override the update method in the serializer to allow that behavior:

class Serializer_UpdateEmployer(ModelSerializer):
    user = Serializer_UpdateUser()
    class Meta:
        model = modelEmployer
        fields = [
            'user',
            'employer_zip',
        ]

    def update(self, instance, validated_data):
        user_data = validated_data.pop('user', {})
        user_serializer = Serializer_UpdateUser(instance.user, data=user_data)
        user_serializer.save()
        return instance

Another solution is to use drf-writable-nested. It automatically makes your nested serializers updatable.

from drf_writable_nested import WritableNestedModelSerializer

class Serializer_UpdateEmployer(WritableNestedModelSerializer):
    user = Serializer_UpdateUser()
    class Meta:
        model = modelEmployer
        fields = [
            'user',
            'employer_zip',
        ]

推荐阅读