Instance for nested serializer is not viewable

Using Django Rest Framework 3.1 I am doing the following:

# models.py

class OrganizationUser(models.Model):
    user = models.ForeignKey(USER_MODEL)
    organization = models.ForeignKey(ORGANIZATION_MODEL)

# serializers.py

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = get_user_model()

class OrganizationUserSerializer(serializers.ModelSerializer):

    user = UserSerializer()

    class Meta:
        model = OrganizationUser

      

I've simplified some of the above code to isolate the problem.

The problem I'm running into is that when I try to update the OrganizationUser via the viewet, I get a validation error:

{"user":{"username":["This field must be unique."]}}

      

In debugging, I found that the error was caused by UniqueValidator and because the custom instance is not set in the parent username field (i.e. UserSerializer).

So, I added the following implementation to_internal_value to OrganizationUserSerializer and then it worked correctly:

def to_internal_value(self, data):

    if self.instance:

        # set user instance on its serializer
        user = self.instance.user
        self.fields['user'].instance = user

        # make sure correct user is specified in request data
        try:
            user_id = self.initial_data['user']['id']
        except KeyError:
            raise fw_serializers.ValidationError('User must be specified')

        if user_id != user.id:
            raise fw_serializers.ValidationError('Invalid user specified')

    return super(OrganizationUserSerializer, self).to_internal_value(data)

      

But I thought the REST Framework would do it automatically? Isn't that so? Is the application responsible for finding any nested serializer instances?

+3


source to share


1 answer


You can implement this behavior by changing the UserSerializer to_internal_value method:

def to_internal_value(self, data):
    if data and data.get('username'):
        return self.Meta.model.objects.get(username=data['username'])
    return super().to_internal_value(data)

      



So now, if you are sending some data to a UserSerializer that has the username as part of the data, it is assumed that you are sending data belonging to an existing object, view it, and return it.

+1


source







All Articles