Django - Отправка post-запроса с использованием вложенного сериализатора с отношениями "многие ко многим". Получение [400 код ошибки] "Это поле не может быть null] ошибка"
Я довольно новичок в Django и пытаюсь сделать POST запрос с вложенными объектами. Вот данные, которые я отправляю:
{
"id":null,
"deleted":false,
"publishedOn":2022-11-28,
"decoratedThumbnail":"https"://i.ytimg.com/vi/a2lC4V479hQ/maxresdefault.jpg,
"rawThumbnail":"https"://i.ytimg.com/vi/a2lC4V479hQ/maxresdefault.jpg,
"videoUrl":"https"://www.youtube.com/watch?v=cl60ToTvG8w,
"title":"Video with tags",
"duration":120,
"visibility":1,
"tags":[
{
"id":null,
"videoId":null,
"videoTagId":42
}
]
}
Вот краткая диаграмма взаимоотношений этих объектов в базе данных
Я хочу создать видео и передать массив вложенных данных, чтобы я мог создать несколько тегов, которые могут быть связаны с видео в отношениях "многие ко многим". В связи с этим поле 'id' видео будет равно нулю, и 'videoId' внутри объекта тега также будет равно нулю при передаче данных. Однако я продолжаю получать ошибку 400 (Bad request), говорящую {tags: [{videoId: [This field may not be null.]}]}
Я пытаюсь переопределить метод create
внутри VideoManageSerializer
, чтобы я мог извлечь теги и после создания видео использовать это видео для создания этих тегов. Мне кажется, что я даже не дохожу до части метода create
внутри VideoManageSerializer
, поскольку видео не создается в базе данных. Я застрял на этом вопросе уже несколько дней. Если кто-нибудь может направить меня в правильном направлении, я буду очень признателен.
Я использую следующие сериализаторы:
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
Вещи, которые изменились -
- Добавил новое поле
write_only
с именемvideo_tag_id
, которое должно было принимать "список PKs изVideoTag
" . - Изменили поле
tags
наread_only
так, что оно не будет участвовать в процессе валидации, но вы получите "вложенный сериализованный вывод". - Changed
create(...)
метод для взаимодействия с новыми изменениями. - Полезная нагрузка 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] }