我是Django的新手,我正在try 用嵌套对象发出POST请求.这是我要发送的数据:

{
   "id":null,
   "deleted":false,
   "publishedOn":2022-11-28,
   "decoratedThumbnail":"https://t3.ftcdn.net/jpg/02/48/42/64/360_F_248426448_NVKLywWqArG2ADUxDq6QprtIzsF82dMF.jpg",
   "rawThumbnail":"https://t3.ftcdn.net/jpg/02/48/42/64/360_F_248426448_NVKLywWqArG2ADUxDq6QprtIzsF82dMF.jpg",
   "videoUrl":"https://www.youtube.com/watch?v=jNQXAC9IVRw",
   "title":"Video with tags",
   "duration":120,
   "visibility":1,
   "tags":[
      {
         "id":null,
         "videoId":null,
         "videoTagId":42
      }
   ]
}

下面是这些对象在数据库上的关系的简图

enter image description here

我想创建一个视频并传入一个嵌套数据数组,这样我就可以创建多个标记,这些标记可以在多对多关系中与视频相关联.正因为如此,当发送数据时,视频的‘id’字段将为空,并且标签对象内的‘avioID’也将为空.然而,我一直收到400 (Bad request)错误,显示为{tags: [{videoId: [This field may not be null.]}]}

我正在try 覆盖VideoManageSerializer中的create方法,这样我就可以提取标签,在创建视频之后,我可以使用该视频来创建那些标签.我甚至不认为我正在进入VideoManageSerializer中的create方法部分,因为视频不是在数据库中创建的.我在这个问题上困了好几天了.如果有人能为我指明正确的方向,我将不胜感激.

我正在使用以下序列化程序:

class VideoManageSerializer(serializers.ModelSerializer):
    tags =  VideoVideoTagSerializer(many=True)

    class Meta:
        model = Video
        fields = ('__all__')
    
    # POST
    def create(self, validated_data):
        tags = validated_data.pop('tags')
        video_instance = Video.objects.create(**validated_data)
        for tag in tags:
            VideoVideoTag.objects.create(video=video_instance, **tag)
        return video_instance

class VideoVideoTagSerializer(serializers.ModelSerializer):
    class Meta:
        model = VideoVideoTag
        fields = ('__all__')

这是使用VideoManageSerializer的视图

class VideoManageViewSet(GenericViewSet,  # generic view functionality
                 CreateModelMixin,  # handles POSTs
                 RetrieveModelMixin,  # handles GETs 
                 UpdateModelMixin,  # handles PUTs and PATCHes
                 ListModelMixin):
    serializer_class = VideoManageSerializer
    queryset = Video.objects.all()

这些都是我正在使用的型号:

class Video(models.Model):
    decoratedThumbnail = models.CharField(max_length=500, blank=True, null=True)
    rawThumbnail = models.CharField(max_length=500, blank=True, null=True)
    videoUrl = models.CharField(max_length=500, blank=True, null=True)
    title = models.CharField(max_length=255, blank=True, null=True)
    duration = models.PositiveIntegerField()
    visibility = models.ForeignKey(VisibilityType, models.DO_NOTHING, related_name='visibility')
    publishedOn = models.DateField()
    deleted = models.BooleanField(default=0)
    
    class Meta:
        managed = True
        db_table = 'video'

class VideoTag(models.Model):
    name = models.CharField(max_length=100, blank=True, null=True)
    deleted = models.BooleanField(default=0)

    class Meta:
        managed = True
        db_table = 'video_tag'

class VideoVideoTag(models.Model):
    videoId = models.ForeignKey(Video, models.DO_NOTHING, related_name='tags', db_column='videoId')
    videoTagId = models.ForeignKey(VideoTag, models.DO_NOTHING, related_name='video_tag', db_column='videoTagId')

    class Meta:
        managed = True
        db_table = 'video_video_tag'

推荐答案

我会考虑按如下方式更改序列化程序,

class VideoManageSerializer(serializers.ModelSerializer):
    video_tag_id = serializers.PrimaryKeyRelatedField(
        many=True,
        queryset=VideoTag.objects.all(),
        write_only=True,
    )
    tags = VideoVideoTagSerializer(many=True, read_only=True)

    class Meta:
        model = Video
        fields = "__all__"

    # POST
    def create(self, validated_data):
        tags = validated_data.pop("video_tag_id")
        video_instance = Video.objects.create(**validated_data)
        for tag in tags:
            VideoVideoTag.objects.create(videoId=video_instance, videoTagId=tag)
        return video_instance

已经改变的事情-

  1. 添加了一个名为101的新的103字段,该字段应该接受"list of PKs of 102".
  2. 100字段更改为103,因此它不会参与验证过程,但您将获得"nested serialized output".
  3. 改变了100种方法,以配合新的变化.
  4. POST有效载荷已更改如下(请注意,已移除tags个,引入video_tag_id个)
    {
       "deleted":false,
       "publishedOn":"2022-11-28",
       "decoratedThumbnail":"https://t3.ftcdn.net/jpg/02/48/42/64/360_F_248426448_NVKLywWqArG2ADUxDq6QprtIzsF82dMF.jpg",
       "rawThumbnail":"https://t3.ftcdn.net/jpg/02/48/42/64/360_F_248426448_NVKLywWqArG2ADUxDq6QprtIzsF82dMF.jpg",
       "videoUrl":"https://www.youtube.com/watch?v=jNQXAC9IVRw",
       "title":"Video with tags",
       "duration":120,
       "visibility":1,
       "video_tag_id":[1,2,3]
    }
    

参考文献

  1. DRF: Simple foreign key assignment with nested serializer?
  2. DRF - write_only
  3. DRF - read_only

Python相关问答推荐

如何让剧作家等待Python中出现特定cookie(然后返回它)?

如何使用数组的最小条目拆分数组

如何在Django基于类的视图中有效地使用UTE和RST HTIP方法?

如何在Python中并行化以下搜索?

两个pandas的平均值按元素的结果串接元素.为什么?

如何创建一个缓冲区周围的一行与manim?

Flask Jinja2如果语句总是计算为false&

Pandas:填充行并删除重复项,但保留不同的值

在Docker容器(Alpine)上运行的Python应用程序中读取. accdb数据库

使用__json__的 pyramid 在客户端返回意外格式

在我融化极点数据帧之后,我如何在不添加索引的情况下将其旋转回其原始形式?

如何使用pytest在traceback中找到特定的异常

在round函数中使用列值

以极轴表示的行数表达式?

Pandas:使列中的列表大小与另一列中的列表大小相同

将索引表转换为Numy数组

是否从Python调用SHGetKnownFolderPath?

matplotlib散点图与NaNs和cmap colored颜色 矩阵

在行数据为向量的DataFrame上计算逐行更改

用考克斯回归的生存分析系列的真值是模棱两可的.