【问题标题】:Django Rest Framework returns 302 on PUT and PATCH and doesn't update anythingDjango Rest Framework 在 PUT 和 PATCH 上返回 302 并且不更新任何内容
【发布时间】:2020-07-11 22:36:51
【问题描述】:

我编写了应该更新模型对象实例的序列化程序和视图。 当我通过 Django Rest Browsable API 测试 API 时,该过程运行良好,但当我使用 curl 时却不行。 curl 请求(GET、PATCH 和 PUT)在服务器上显示 302 并且方法为 patch 时没有更新:

curl 命令是:

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

对于 curl 命令,服务器给出:

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

而可浏览 api 中的相同更新提供:

[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

查看:

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)

序列化器

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

型号

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)

我看到了许多与此问题相近的问题,但我没有找到任何有效的答案......看起来很简单,但我很迷茫......

【问题讨论】:

  • 您的 django i18n 设置将请求重定向到 /wf/.../en/wf/...。如您所见,您的 curl 与浏览器 api 的 url 不同。只需在您的 curl 请求中使用正确的 url(以语言 en/fr/ 开头)。或者为您的 API 调用禁用 url 重定向。
  • 302 重定向总是会导致 GET,因此您必须避免在 API 中进行重定向。
  • 哇!看起来很明显。如果我添加一些语言来为路径添加前缀,它现在可以工作。非常感谢@dirkgroten 的帮助。附属问题:有没有办法只为rest框架删除i18n?
  • Django 不会自动将语言前缀添加到 url,您已经要求 Django 通过在 URL 配置中添加 i18n_patterns 来做到这一点。只需为那些应该拥有它的 URL 添加它,并为您在 API 中使用的 URL 删除它(例如,将其用于 /blog,但不适用于 /api。)
  • 好的。完美的 !而已。你让我很快乐。 非常感谢 @dirkgroten

标签: python django curl django-rest-framework put


【解决方案1】:

您看到的重定向来自您的 i18n 设置:您正在向 /wf/... 提交 PUT 或 PATCH 请求,而 Django 重定向到 /en/wf/...

302 重定向总是会导致后续的 GET 请求,这就是为什么您看不到任何错误但也没有保存任何内容的原因。

所以要么:

  • 向 API 提交您的请求,并在 URL 前加上语言 (/en/wf/...)
  • 或者为您的 API 网址禁用网址语言前缀。

您可以通过不在您的 url 配置中的 i18n_patterns 中包含您的 API url 来执行后者。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-14
    • 2017-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    相关资源
    最近更新 更多