gkl
gkl

Reputation: 339

Django REST Framework PATCH fails on required fields

We are creating an API that needs to allow a user to update a record. In many cases, like a status update or name change, only one field will change. This seems an appropriate use-case scenario for a PATCH request. As I understand it this is a 'partial' update.

We've implemented Django's REST Framework and run into this issue. For a record such as a "AccountUser" I want to change a name field only so I send the following request: PATCH /api/users/1/ HTTP/1.1 Host: localhost X-CSRFToken: 111122223333444455556666 Content-Type: application/json;charset=UTF-8 Cache-Control: no-cache

{ "fullname": "John Doe" }

The record obviously has other attributes including a couple of 'related' fields such as 'account' which is required for a new record. When submit the request, the response is a 400 error with the following body: { "account": [ "This field is required." ] } The serializer for the user looks like this:

class AccountUserSerializer(serializers.ModelSerializer):
    account = serializers.PrimaryKeyRelatedField()

class Meta:
    model = AccountUser
    fields = ('id', 'account', 'fullname', ... )
    depth = 1

And the model looks like this:

class AccountUser(models.Model):
    ''' Account User'''
    fullname = models.CharField(max_length=200,
        null=True,blank=True)
    account = models.ForeignKey(Account,
        on_delete=models.PROTECT
        )

    objects = AccountUserManager()

    def __unicode__(self):
        return self.email

    class Meta:
        db_table = 'accounts_account_user'

Am I doing something wrong here or is it wrong to expect to be able to update a single field on a record this way. Thanks! This community rocks!

EDIT: Requested - AccountUserManager:

class AccountUserManager(BaseUserManager):

    def create_user(self, email, account_name):
        username = hash_email_into_username(email)
        ...
        account = Account.objects.get(name=account_name)
        account_user = AccountUser(email=email,user=user,account=account)
        account_user.save()
        return account_user

Upvotes: 8

Views: 7261

Answers (5)

Ayush Bisht
Ayush Bisht

Reputation: 1

you can simply add this line after the fields variable in serializers.py

class AccountUserSerializer(serializers.ModelSerializer):
    account = serializers.PrimaryKeyRelatedField()

class Meta:
    model = AccountUser
    fields = ('id', 'account', 'fullname', ... )
    depth = 1
    extra_kwargs = {
            'account' : {'required' : False}
        }

Upvotes: 0

arcanemachine
arcanemachine

Reputation: 720

In my case, all I had to do was add required=False to my serializer field's arguments.

A novice mistake to be sure, but I thought I'd mention it here in case it helps anyone.

Upvotes: 1

John Pang
John Pang

Reputation: 2503

I came here because I got into a similar problem. CREATE is fine but PATCH isn't.

Since OP doesn't post the ViewSets and I suspend if he is using a custom ViewSets, which I got a mistake when override the update function:

class MyViewSet(ModelViewSet):
    def update(self, request, *args, **kwargs):
        // Do some checking
        return super().update(request, args, kwargs)

My mistake is in the call to super(). Missing the asterisks. This fix my problem

        return super().update(request, *args, **kwargs)

Upvotes: 1

M.Void
M.Void

Reputation: 2894

See my answer about partial updates. Also you can see the drf docs and this one docs

Upvotes: 1

Kevin Stone
Kevin Stone

Reputation: 8981

It doesn't look like your manager is filtering the user. I'd encourage you to use pdb and set a breakpoint in your view code and step through to see why its attempting to create a new record. I can vouch that we use PATCH to complete partial updates all the time and only send a few fields to update without issue.

Only other thought is that you're some how sending a value for account (like null) that's triggering the validation error even though you're listed example only shows sending the fullname field.

Upvotes: 2

Related Questions