简体   繁体   中英

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

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.

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

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)

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.

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}
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM