Skip to main content
 首页 » 编程设计

python之Django Rest Framework之使用 ModelSerializer 和 ModelViewSet 更新相关模型

2024年08月14日51insus

背景

我有两个序列化器: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。 (省略代码)

目标

目标很简单。

问题

我收到 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 .

因此,我的问题的主要概念可以缩小为以下内容。

  1. 我应该如何修复请求的数据字段,以便 ModelViewSet 的 update() 方法中的验证可以通过?
  2. 我是否必须覆盖 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 值,然后在循环之前检查照片数据是否已提供。