Peter Jordanson
Peter Jordanson

Reputation: 91

Enforce that only certain attributes can be changed using a PUT request in Django

I want to make it so a user is able to update only certain attributes with a PUT request in my Django Rest API. As an example, if I had the following model and only wanted the user to be able to update their first and last name, how would I go about doing this?

models.py:

class User(models.Model):
    email = models.EmailField('email address', unique = True)
    first_name = models.TextField(max_length = 10)
    last_name = models.TextField(max_length = 20)

(noting that they should not be able to change the 'id' field either which is automatically set)

serializers.py:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'email', 'first_name', 'last_name']

views.py:

class SingleUser(APIView):
    def put(self, request, user_id):
        user = User.objects.get(pk = user_id)
        serializer = UserEditSerializer(user, data = request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status = status.HTTP_200_OK)
        return Response(serializer.errors, status = status.HTTP_400_BAD_REQUEST)

What is the best way to enforce that users can only change a subset of these attributes?

Thanks, Grae

Upvotes: 1

Views: 1447

Answers (3)

gmacro
gmacro

Reputation: 427

You can use the read_only_fields, a serializer's attribute.

Another approach is to use a "serializer per action"

Upvotes: 0

JPG
JPG

Reputation: 88549

Create a separate serializer and use it

# serializers.py
class UserPutSerializer(serializers.ModelSerializer): # new serializer class
    class Meta:
        model = User
        fields = ['first_name', 'last_name'] # define required fields

#views.py
class SingleUser(APIView):
    def put(self, request, user_id):
        user = User.objects.get(pk=user_id)
        serializer = UserPutSerializer(user, data=request.data) # use new serializer here
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Upvotes: 2

Nico Griffioen
Nico Griffioen

Reputation: 5405

You can set read-only fields on a serializer:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'email', 'first_name', 'last_name']
        read_only_fields = ['id', 'email']

Make sure to set your serializer to partial in the put function:

serializer = UserEditSerializer(user, data = request.data, partial=True)

You could also omit fields from the serializer altogether, which will make the fields not available to the user at all.

Upvotes: 3

Related Questions