0

I'm having trouble in using patch method inside a ModelViewSet for my custom User model. Here is the code:

views.py

@permission_classes([IsAdminUser])
    class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    http_method_names = ['get', 'post', 'patch', 'head', 'delete']

serializers.py

class UserSerializer(serializers.ModelSerializer):
class Meta:
    model = User
    fields = ('id',
              'email',
              'password',
              'is_active',
              'is_staff',
              'is_admin')
    extra_kwargs = {'password': {'write_only': True, 'required': True},
                    'is_active': {'default': True},
                    'is_staff': {'default': False},
                    'is_admin': {'default': False}}

def create(self, validated_data):
    self.is_valid(raise_exception=True)
    if validated_data['is_admin']:
        validated_data['is_staff'] = True
    user = User.objects.create_user(**validated_data)
    return user

def update(self, instance, validated_data):
    instance.email = validated_data.get('email')
    instance.is_active = validated_data.get('is_active')
    instance.is_staff = validated_data.get('is_staff')
    instance.is_admin = validated_data.get('is_admin')
    if instance.is_admin:
        instance.is_staff = True
    instance.save()
    return instance

I set a permission in order to allow only superuser to access this view. The problem comes when trying to perform a patch. For example, if I try to change is_staff attribute to False of a User using Postman with PATCH and "http://localhost:8000/users/USER_ID", I get the following error:

django.db.utils.IntegrityError: null value in column "email" violates not-null constraint DETAIL: Failing row contains (1, pbkdf2_sha256$180000$6jePqBspO6xK$tCQ9zZk1uOdJD2F7L9BQRFFDbz1GXJ..., 2020-04-18 20:02:57.052639+00, null, t, t, t).

It seems like django asks me to provide every single field fo User model (email, is_active, is_staff, is_admin), which it doesn't make sense in my opinion givien that it's a PATCH request. To overcome the issue, I've modified the update method of my UserSerializer like that:

    def update(self, instance, validated_data):
        if validated_data.get('email') is not None:
            instance.email = validated_data.get('email')
        if validated_data.get('is_active') is not None:
            instance.is_active = validated_data.get('is_active')
        if validated_data.get('is_staff') is not None:
            instance.is_staff = validated_data.get('is_staff')
        if validated_data.get('is_admin') is not None:
            instance.is_admin = validated_data.get('is_admin')
        if instance.is_admin:
            instance.is_staff = True
        instance.save()
        return instance

It works now, but I'd like to know whether this is a good solution. In my opinion, it is not a "canonical" way for solving the problem. I've also tried to override partial_update method (following others StackOverflow's answers) inside my UserViewSet, with no results.

2

1 Answer 1

0

I've found very useful this previous post django-rest-framework-serializer-update-method-does-not-save-object The problem was in the serializer. I've changed the overwritten update method inside my UserSerializer and now PATCH works

def update(self, instance, validated_data):
    if validated_data.get('is_admin'):
        validated_data['is_staff'] = True
    return super().update(instance, validated_data)

NOTE: no need to override any method in the view, just add 'patch' to http_method_names list

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.