Brad Reardon Brad Reardon - 2 months ago 12
reST (reStructuredText) Question

Django Rest Framework: Disable field update after object is created

I'm trying to make my User model RESTful via Django Rest Framework API calls, so that I can create users as well as update their profiles.

However, as I go through a particular verification process with my users, I do not want the users to have the ability to update the username after their account is created. I attempted to use read_only_fields, but that seemed to disable that field in POST operations, so I was unable to specify a username when creating the user object.

How can I go about implementing this? Relevant code for the API as it exists now is below.

class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'password', 'email')
write_only_fields = ('password',)

def restore_object(self, attrs, instance=None):
user = super(UserSerializer, self).restore_object(attrs, instance)
user.set_password(attrs['password'])
return user


class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
serializer_class = UserSerializer
model = User

def get_permissions(self):
if self.request.method == 'DELETE':
return [IsAdminUser()]
elif self.request.method == 'POST':
return [AllowAny()]
else:
return [IsStaffOrTargetUser()]


Thanks!

Answer

It seems that you need different serializers for POST and PUT methods. In the serializer for PUT method you are able to just except the username field (or set the username field as read only).

class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    serializer_class = UserSerializer
    model = User

    def get_serializer_class(self):
        serializer_class = self.serializer_class

        if self.request.method == 'PUT':
            serializer_class = SerializerWithoutUsernameField

        return serializer_class

    def get_permissions(self):
        if self.request.method == 'DELETE':
            return [IsAdminUser()]
        elif self.request.method == 'POST':
            return [AllowAny()]
        else:
            return [IsStaffOrTargetUser()]

Check this question django-rest-framework: independent GET and PUT in same URL but different generics view

Comments