【发布时间】: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