update() throwing TypeError: serializer.update() got an unexpected keyword argument 'data'

Viewed 3797

I'm trying to update an already db-saved object once it has successfully sent a message. it calls the update() method of the serializer class in order to achieve this. This is the model that will have it's instance updated:

class SMSMessages(models.Model):
    sms_number_to = models.CharField(max_length=14)
    sms_content = models.CharField(max_length=160)
    sending_user = models.ForeignKey("SMSUser", on_delete=models.PROTECT, related_name="user_that_sent")
    sent_date = models.DateTimeField(auto_now=True)
    delivery_status = models.BooleanField(default=False)

    class Meta:
        verbose_name_plural = "SMSMessages"

    def __str__(self):
        return str(self.sending_user)

This is the serializer class I'm using:

class SMSMessagesSerializer(serializers.ModelSerializer):
    """
    A class for serializing the SMSMessages model's data. It sub-classes the
    ModelSerializer class from serializer's module.
    """

    class Meta:
        model = SMSMessages
        fields = '__all__'

        def update(self, instance, validated_data):
            """
            This method is used to update an instance of the SMSMessages's delivery_status attribute.
            It get's the value for delivery_status from the input parameter, updates the specific instance
            of the SMSMessagesSerializer, saves that instance and returns it.
            """
            instance = self.get_object()
            instance.delivery_status = validated_data.get('delivery_status', instance.delivery_status)
            instance.save()
            return instance

and this is the APIView class that has the POST method that will update the if the message is successfully sent:

class SMSView(APIView):
    """
    This class is responsible for all the method operations of an sms. It provides implementations for the GET, POST, and OPTIONS methods.
    Each method provides it's own description.
    """

    serializer_class = SMSMessagesSerializer

    def get(self, request):
        """
        This method is used to GET all created instance of the SMSMessages class that are saved in the db.
        """
        queryset = SMSMessages.objects.filter(sending_user=request.user)
        while queryset:
            return Response(
                data={
                    queryset.values()
                    },
                status=status.HTTP_200_OK,
                content_type="application/json"
            )
        else:
            return Response(
                data={
                    "no sms has been sent"
                },
                status=status.HTTP_404_NOT_FOUND,
                content_type="application/json"
            )

    def post(self, request):
        """
        This method is used to create an instance of the SMSMessages indirectly by using the SMSMessagesSerializer.
        If that is valid it will be passed to the sender() method from the notification.sender module. The serializer
        will be saved, aka the object will be saved to the database, and then the sender() is called. It will run three
        times before it gives up and fails. Once that returns a True value the instance will be called, aka the object
        will be saved to the database, with a delivery_status value of True.
        """
        sms_messages_serializer = SMSMessagesSerializer(
            data={
                "sms_number_to": request.data.get("sms_number_to"),
                "sms_content": request.data.get("sms_content"),
                "sending_user": request.data.get("sending_user")
            }
        )
        permission_classes = (permissions.IsAuthenticated)

        if sms_messages_serializer.is_valid():
            data_to_send = {
                "number": sms_messages_serializer.validated_data[
                    "sms_number_to"
                ],
                "msg_text": sms_messages_serializer.validated_data[
                    "sms_content"
                ]
            }
            sms_messages_serializer.save()

        # TODO refactor this into it's own function
        max_retry = 0
        resp = Response()
        while max_retry < 3:
            max_retry += 1
            status_flag, status_response = sender(data_to_send)
            if not status_flag:
                resp = Response(
                    data={
                        "error": f"{status_response.text}"
                    },
                    status=status_response.status_code,
                    content_type="application/json"
                )
            else:
                sms_messages_serializer.update(
                    data={
                        "delivery_status": True
                    },
                    partial=True
                )
                resp = Response(
                    data={
                        "success": f"{status_response.json()}"
                    },
                    headers=status_response.headers,
                    status=status_response.status_code,
                    content_type="application/json"
                )
                return resp
        else:
            resp = Response(
                data={
                    "error": "unable to send sms"
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
                content_type="application/json"
            )
            return resp

It will be accessed via the following urlpattern:

urlpatterns = [
    path('sendsms/', SMSView.as_view(), name="send_sms"),
    path('viewsms/', SMSView.as_view(), name="view_sms"),
]

But instead of successfully updating the instance using python sms_messages_serializer.update(data={"delivery_status": True}partial=True) it throws TypeError: serializer.update() got an unexpected keyword argument 'data'.

I've tried to change the update in the SMSMessagesSerializer class to no avail and tried renameing the data attribute to validated_data or value but still it doesn't work. I need it to update the delivery_status to True once it sends the sms, how can I be able to do that?

2 Answers

for anyone that might run into this problem, I fixed it by changing the sms_messages_serializer.update() method in the post() metho to this:

 sms_messages_serializer.update(sms_object,{"delivery_status": True})

where sms_object=sms_object = sms_messages_serializer.save(), meaning the instance of sms_messages_serializer after the data has been validated & saved.

no need for data attribute or partial=True

It was giving this error message to me and in my case it was lack of attention. I'll put my solution here for other people who have the same error: I had put the model'name and not the serializer'name here:

Wrong:

class FooViewSet(viewsets.ModelViewSet):
    serializer_class = Foo_model_name

Right:

class FooViewSet(viewsets.ModelViewSet):
    serializer_class = Foo_serializer_name
Related