HTTP PUT 在 Django 休息框架中无法正常工作
HTTP PUT not working properly in django rest framework
我在 django rest 框架中使用以下代码来实现放置和修补功能。 PATCH (partial_update) 工作正常,但是,为 PUT 提供更少的字段不会像 PUT 请求那样替换整个资源。例如,如果数据如下所示:
{
"id": 6,
"name": "crticial MVP",
"description": "getting things done",
"end": "2012-02-18"
}
如果我尝试使用以下数据进行 PUT(在 http://localhost:800/api/sprints/6/ 上):
{
"name": "critical MVP2",
"end": "2012-02-18"
}
此调用应将描述设置为 none。但是描述保留了它的价值,就好像我在做一个 PATCH 一样。我将如何在更新功能中强制执行资源替换?
PS: 我在为更新初始化序列化程序时设置了 partial=False。
views.py:
class SprintViewSet(viewsets.ModelViewSet):
queryset = Sprint.objects.order_by('end')
serializer_class = SprintSerializer
def update(self, request, *args, **kwargs):
sprint=self.get_object()
serializer = SprintSerializer(sprint, data=request.data, partial=False,
context={'request': request, 'view':self, 'format':None})
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
def partial_update(self, request, *args, **kwargs):
instance = self.get_object()
serializer = SprintSerializer(instance, data=request.data, partial=True,
context={'request': request, 'view':self, 'format':None})
serializer.is_valid(raise_exception=True)
new_instance = serializer.save()
return Response(serializer.data)
serializers.py:
class SprintSerializer(serializers.ModelSerializer):
links = serializers.SerializerMethodField()
class Meta:
model = Sprint
fields = ('id', 'name', 'description', 'end', 'links')
def get_links(self, obj):
request = self.context['request']
return {
'self': reverse('sprint-detail',
kwargs={'pk': obj.pk},request=request),
}
models.py
class Sprint(models.Model):
name = models.CharField(max_length=100, blank=True, default='')
description = models.TextField(blank=True, default='')
end = models.DateField(unique=True)
def __str__(self):
return self.name or _('Sprint ending %s') % self.end
A PUT
期望传入完整的数据对象,所以模型上的任何属性都被传入的数据替换。但这需要传入完整的数据对象,所以如果您不传入一个字段,那么它将被忽略,具体取决于数据的发送方式。
如果您使用表单数据发送数据(AJAX 没有 JSON,或者 HTML <form>
),那么该字段将被完全忽略。这主要与某些浏览器在未设置值时不发送某些字段(例如复选框)有关,因此 DRF 在这些情况下手动覆盖它。
如果您正在使用 JSON 并且该字段不是必需的(这似乎是您的情况),DRF 只会在将密钥传递到请求中时覆盖该值。这是因为 PUT
应该 包含 一个完整的数据对象,并且 DRF 基于此做出一些假设。
我在 django rest 框架中使用以下代码来实现放置和修补功能。 PATCH (partial_update) 工作正常,但是,为 PUT 提供更少的字段不会像 PUT 请求那样替换整个资源。例如,如果数据如下所示:
{
"id": 6,
"name": "crticial MVP",
"description": "getting things done",
"end": "2012-02-18"
}
如果我尝试使用以下数据进行 PUT(在 http://localhost:800/api/sprints/6/ 上):
{
"name": "critical MVP2",
"end": "2012-02-18"
}
此调用应将描述设置为 none。但是描述保留了它的价值,就好像我在做一个 PATCH 一样。我将如何在更新功能中强制执行资源替换?
PS: 我在为更新初始化序列化程序时设置了 partial=False。
views.py:
class SprintViewSet(viewsets.ModelViewSet):
queryset = Sprint.objects.order_by('end')
serializer_class = SprintSerializer
def update(self, request, *args, **kwargs):
sprint=self.get_object()
serializer = SprintSerializer(sprint, data=request.data, partial=False,
context={'request': request, 'view':self, 'format':None})
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
def partial_update(self, request, *args, **kwargs):
instance = self.get_object()
serializer = SprintSerializer(instance, data=request.data, partial=True,
context={'request': request, 'view':self, 'format':None})
serializer.is_valid(raise_exception=True)
new_instance = serializer.save()
return Response(serializer.data)
serializers.py:
class SprintSerializer(serializers.ModelSerializer):
links = serializers.SerializerMethodField()
class Meta:
model = Sprint
fields = ('id', 'name', 'description', 'end', 'links')
def get_links(self, obj):
request = self.context['request']
return {
'self': reverse('sprint-detail',
kwargs={'pk': obj.pk},request=request),
}
models.py
class Sprint(models.Model):
name = models.CharField(max_length=100, blank=True, default='')
description = models.TextField(blank=True, default='')
end = models.DateField(unique=True)
def __str__(self):
return self.name or _('Sprint ending %s') % self.end
A PUT
期望传入完整的数据对象,所以模型上的任何属性都被传入的数据替换。但这需要传入完整的数据对象,所以如果您不传入一个字段,那么它将被忽略,具体取决于数据的发送方式。
如果您使用表单数据发送数据(AJAX 没有 JSON,或者 HTML <form>
),那么该字段将被完全忽略。这主要与某些浏览器在未设置值时不发送某些字段(例如复选框)有关,因此 DRF 在这些情况下手动覆盖它。
如果您正在使用 JSON 并且该字段不是必需的(这似乎是您的情况),DRF 只会在将密钥传递到请求中时覆盖该值。这是因为 PUT
应该 包含 一个完整的数据对象,并且 DRF 基于此做出一些假设。