David
David

Reputation: 502

Django Rest Framework returns 302 on PUT and PATCH and doesn't update anything

I've coded serializer and views that should update instances of a model object. When I test the API through THe Django Rest Browsable API, the process works fine but it doesn't when I use curl. curl requests (GET, PATCH and PUT) shows 302 on the server and nothing is updated when method is patch:

curl command is :

curl -X PATCH -H "Content-Type: application/json" -d '{ "status": "undefined", "started_at": "2022-03-31T08:22:54"}' http://localhost:8000/wf/machineworks/b79ac69b-e9a6-410b-bfbd-a79b0163f69a

and, for the curl command, the server gives :

[31/Mar/2020 12:50:33] "PATCH /wf/machineworks/b79ac69b-e9a6-410b-bfbd-a79b0163f69a HTTP/1.1" 302 0

whereas the same update in the browsable api gives :

[31/Mar/2020 13:20:25] "PATCH /fr/wf/machineworks/b79ac69b-e9a6-410b-bfbd-a79b0163f69a/ HTTP/1.1" 200 12588
__ here is the curl log :__
== Info:   Trying 127.0.0.1...
== Info: TCP_NODELAY set
== Info: Connected to localhost (127.0.0.1) port 8000 (#0)
=> Send header, 184 bytes (0xb8)
0000: PATCH /wf/machineworks/b79ac69b-e9a6-410b-bfbd-a79b0163f69a HTTP
0040: /1.1
0046: Host: localhost:8000
005c: User-Agent: curl/7.58.0
0075: Accept: */*
0082: Content-Type: application/json
00a2: Content-Length: 61
00b6:
=> Send data, 61 bytes (0x3d)
0000: { "status": "undefined", "started_at": "2022-03-31T08:22:54"}
== Info: upload completely sent off: 61 out of 61 bytes
<= Recv header, 20 bytes (0x14)
0000: HTTP/1.1 302 Found
<= Recv header, 37 bytes (0x25)
0000: Date: Tue, 31 Mar 2020 11:13:27 GMT
<= Recv header, 38 bytes (0x26)
0000: Server: WSGIServer/0.2 CPython/3.6.9
<= Recv header, 40 bytes (0x28)
0000: Content-Type: text/html; charset=utf-8
<= Recv header, 69 bytes (0x45)
0000: Location: /en/wf/machineworks/b79ac69b-e9a6-410b-bfbd-a79b0163f6
0040: 9a/
<= Recv header, 14 bytes (0xe)
0000: Vary: Cookie
<= Recv header, 33 bytes (0x21)
0000: X-Content-Type-Options: nosniff
<= Recv header, 19 bytes (0x13)
0000: Connection: close
<= Recv header, 2 bytes (0x2)
0000:
<= Recv data, 0 bytes (0x0)
== Info: Closing connection 0

view:

class MachineWorkViewset(viewsets.ViewSet):
    """
    A simple ViewSet for listing or retrieving machineworks.
    """
    def get_queryset(self,pk=None):
        if pk:
            return get_object_or_404(MachineWork, pk=pk)
        else:
            return MachineWork.objects.all()

    def list(self, request):
        queryset = self.get_queryset()
        serializer = MachineWorkSerializer(queryset, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk):
        queryset = self.get_queryset(pk)
        serializer = MachineWorkSerializer(queryset)
        return Response(serializer.data)

    def update(self, request, pk):
        queryset = self.get_queryset(pk)
        serializer = MachineWorkSerializer(queryset, data=request.data)
        if serializer.is_valid():
            serializer.save()
        return Response(serializer.data)

    def partial_update(self, request, pk):
        queryset = self.get_queryset(pk)
        serializer = MachineWorkSerializer(queryset, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
        return Response(serializer.data)

serializer

class MachineWorkSerializer(serializers.Serializer):
    uuid =  serializers.ReadOnlyField(source='id')
    task =  serializers.CharField(required=False, allow_blank=True, max_length=10)
    status =  serializers.CharField(required=False, allow_blank=True, max_length=10)
    language =  serializers.ReadOnlyField(source='language.language')
    source =  serializers.ReadOnlyField(source='spotler.transcription')

    started_at = serializers.DateTimeField()
    ended_at = serializers.DateTimeField()

    class Meta:
        model = MachineWork

    def __init__(self, *args, **kwargs):
        super(MachineWorkSerializer,self).__init__(*args,**kwargs)



    def update(self, instance, validated_data):
        """
        Update and return an existing `Snippet` instance, given the validated data.
        """
        instance.status = validated_data.get('status', instance.status)
        instance.started_at = validated_data.get('started_at', instance.started_at)
        instance.ended_at = validated_data.get('ended_at', instance.ended_at)
        instance.save()
        return instance

model

class MachineWork(models.Model):
    ''' 
    '''

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    spotler = models.ForeignKey(Spotler,on_delete=models.CASCADE,verbose_name = _('Spotler'), related_name='machineworks')
    task = models.CharField(max_length=10, choices=TASKS, verbose_name = _('task'), blank=True)
    created_at = models.DateTimeField(default=timezone.now, verbose_name = _('submited at'))
    started_at = models.DateTimeField(auto_now_add=False,  verbose_name = _('started at'), null=True)
    ended_at = models.DateTimeField(auto_now_add=False , verbose_name = _('ended at'), null=True)
    language = models.ForeignKey(Language,on_delete=models.SET_NULL,verbose_name = _('language'), related_name='machineworks', null=True)
    status = models.CharField(max_length=10, choices=STATUS, default='unknown', verbose_name = _('status'), blank=True)

    class Meta:
        verbose_name = _('Machine Works')
        verbose_name_plural = _('Machine Works')
        indexes = [models.Index(fields=['spotler','language']),]

    def stop(self, status='done'):
        self.ended_at = timezone.now()
        self.status = status
        self.save()
        self.spotler.sequencer.refresh()

    def save(self,*args,**kwargs):
        super(MachineWork,self).save(*args,**kwargs)
        self.spotler.sequencer.update(self)

I saw many issues close to this one but I didn't fine any answer that works... Seem simple but I'm quite lost...

Upvotes: 1

Views: 1724

Answers (1)

dirkgroten
dirkgroten

Reputation: 20692

The redirect you're seeing comes from your i18n settings: You're submitting a PUT or PATCH request to /wf/... and Django redirects to /en/wf/....

A 302 redirect will always result in a subsequent GET request, so that's why you don't see any error but also why nothing is being saved.

So either:

  • Submit your request to the API prefixing the URL with the language (/en/wf/...)
  • Or disable URL language prefixing for your API urls.

You can do the latter by not including your API urls in i18n_patterns in your urls config.

Upvotes: 3

Related Questions