背景
我有两个序列化器:PostSerializer 和 PostImageSerializer,它们都继承了 DRF ModelSerializer。 PostImage 模型通过 related_name='photos' 与 Post 链接。
因为我希望序列化程序执行更新,PostSerializer 覆盖了 ModelSerializer 的 update() 方法,如官方 DRF 文档中所述。
class PostSerializer(serializers.ModelSerializer):
photos = PostImageSerializer(many=True)
class Meta:
model = Post
fields = ('title', 'content')
def update(self, instance, validated_data):
photos_data = validated_data.pop('photos')
for photo in photos_data:
PostImage.objects.create(post=instance, image=photo)
return super(PostSerializer, self).update(instance, validated_data)
class PostImageSerializer(serializer.ModelSerializer):
class Meta:
model = PostImage
fields = ('image', 'post')
我还定义了一个ViewSet,它继承了ModelViewSet。
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
最后将 PostViewSet 注册到 DefaultRouter。 (省略代码)
目标
目标很简单。
- 通过 PostMan 发送 PUT 请求,URL 类似于“PUT http://localhost:8000/api/posts/1/” '
- 由于应包含图像文件,请求将通过表单数据完成,例如 below.
问题
我收到 400 响应,错误消息如下。
{
"photos": [ "This field is required." ],
"title": [ "This field is required." ],
"content": [ "This field is required." ]
}
(请注意,错误消息可能与 DRF 错误消息不完全一致,因为它们是经过翻译的。)
很明显,我的 PUT 字段都没有被应用。 所以我一直在挖掘 Django rest 框架源代码本身,并在 ViewSet update() method continues to fail 中发现了序列化程序验证。 .
我对此表示怀疑,因为我不是通过 JSON 而是通过使用键值对的表单数据来 PUT 请求,所以 request.data 没有得到正确验证。
但是,我应该在请求中包含多个图像,这意味着纯 JSON 不起作用。
对于这种情况,最明确的解决方案是什么?
谢谢。
更新
正如 Neil 所指出的,我在 PostSerializer 的 update() 方法的第一行添加了 print(self)。但是我的控制台上没有打印出任何内容。
我认为这是由于我上面的怀疑,因为调用序列化器 update() 方法的 perform_update() 方法被称为 AFTER serializer is validated .
因此,我的问题的主要概念可以缩小为以下内容。
- 我应该如何修复请求的数据字段,以便 ModelViewSet 的 update() 方法中的验证可以通过?
- 我是否必须覆盖 ModelViewSet 的 update() 方法(不是来自 ModelSerializer 的方法)?
再次感谢。
请您参考如下方法:
首先你需要设置header:
Content-Type: multipart/form-data;
But maybe if you set form-data in postman, this header should be default.
您不能将图像作为 json 数据发送(除非您将其编码为字符串并在服务器端解码为图像,例如 base64)。
在 DRF 中,PUT 默认需要所有字段。如果您只想设置部分字段,则需要使用 PATCH。
要解决这个问题并使用 PUT 更新部分字段,您有两个选择:
- 编辑 View 集中的update 方法以部分更新序列化程序
- 编辑路由器以始终在更高级的序列化程序中调用 partial_update 方法
您可以重写 View 集 update 方法以始终更新序列化器部分(仅更改提供的字段):
def update(self, request, *args, **kwargs):
partial = True # Here I change partial to True
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response(serializer.data)
添加
rest_framework.parsers.MultiPartParser
到 REST_FRAMEWORK 字典的主要设置文件:
REST_FRAMEWORK = {
...
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.MultiPartParser',
)
}
看看你的序列化器,很奇怪你没有从 PostSerializer 得到错误,因为你没有将“照片”字段添加到 Meta.fields 元组。
在这种情况下我的更多建议:
- 将 required=False 添加到您的photos 字段(除非您希望这是必填项)
- 如上所述,将 photos 字段添加到 Meta.fields 元组 fields = ('title', 'content', 'photos',)
- 为您的 validated_data.pop('photos') 添加默认的 None 值,然后在循环之前检查照片数据是否已提供。
