ModelViewSet - Update nested field

15,538

Solution 1

A little late, but, Try this,

class OwnerSerializer(serializers.ModelSerializer):
    class Meta:
        model =  Owner
        fields = ('id', 'name')
        extra_kwargs = {
            'id': {
                'read_only': False, 
                'required': True
             }
        } #very important

    def create(self, validated_data):
        # As before.
        ...

    def update(self, instance, validated_data):
        # Update the  instance
        instance.some_field = validated_data['some_field']
        instance.save()

        # Delete any detail not included in the request
        owner_ids = [item['owner_id'] for item in validated_data['owners']]
        for owner in cars.owners.all():
            if owner.id not in owner_ids:
                owner.delete()

        # Create or update owner 
        for owner in validated_data['owners']:
            ownerObj = Owner.objects.get(pk=item['id'])
            if ownerObje:
                ownerObj.some_field=item['some_field']
                ....fields...
            else:
               ownerObj = Owner.create(car=instance,**owner)
            ownerObj.save()

        return instance

Solution 2

Just in-case someone stumbles on this

had the same error in my case but setting read_only to True fixed it for me.

    owner = ownerSerializer(many=False, read_only=True) 

Note that, this field won't appear in the form when posting data to the api.

Share:
15,538

Related videos on Youtube

CheapD AKA Ju
Author by

CheapD AKA Ju

God could create the world in six days because he didn't have to make it compatible with the previous version.

Updated on September 15, 2022

Comments

  • CheapD AKA Ju
    CheapD AKA Ju over 1 year

    I'm currently working on Django with Django Rest Framwork.

    I can't update my object within nested object field.


    serializer.py

    class OwnerSerializer(serializers.ModelSerializer):
        class Meta:
            model =  Owner
            fields = ('id', 'name')
    
    class CarSerializer(serializers.ModelSerializer):
        owner = ownerSerializer(many=False, read_only=False) 
        class Meta:
            model =  Car
            fields = ('id', 'name', 'owner')
    

    view.py

    class OwnerViewSet(viewsets.ModelViewSet):
        queryset = Owner.objects.all()
        serializer_class = OwnerSerializer
    
    class CarViewSet(viewsets.ModelViewSet):
        serializer_class = CarSerializer
        queryset = Car.objects.all()
    
        def create(self, request):
            serialized = self.serializer_class(data=request.DATA)
            if serialized.is_valid():
                serialized.save()
                return Response(status=HTTP_202_ACCEPTED)
            else:
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    

    When I do this :

    Request URL:http://localhost:9000/api/v1/cars/1/?format=json
    Request Method:PUT
    Request Paylod :
    {
        "id":1,
        "name": "TEST", 
        "ower": {
            "id":1,
            "name": "owner_test"
        }
    }
    

    I get the following Response :

    The `.update()` method does not support writable nestedfields by default.
    Write an explicit `.update()` method for serializer `app.serializers.CarSerializer`,
    or set `read_only=True` on nested serializer fields.
    

    Knowing :

    • I want to keep the owner serialization on GET;
    • We can imagine the car nested by another object and ect...

    How can I do if i want to change the owner when I update the car.

  • Alex78191
    Alex78191 over 4 years
    It's not working, the same error is here, caanot edit owner from car.
  • Alex78191
    Alex78191 over 4 years
    The question is how to change the owner when I update the car?.
  • ankush981
    ankush981 over 2 years
    @Alex78191 Exactly where I'm stuck at the moment! I need this field as part of a PATCH request so I, of course, should be able to change it but in my use case I also need to be able to make it null on the backend. Thanks, DRF? 😂