如何使用Django Rest Framework反序列化嵌套对象

时间:2015-06-10 19:17:23

标签: json django django-rest-framework

说我有这样的Django模型:

class Book(models.Model):
  title = models.CharField(max_length=150)
  author = models.CharField(max_length=150) 

class Chapter(models.Model):
  book = models.ForeignKey(Book, related_name='chapters')
  title = models.CharField(max_length=150)
  page_num = models.IntegerField()

和Django Rest Framework类是这样的:

class ChapterSerializer(serializers.ModelSerializer):
  class Meta:
    model = Chapter
    fields = ('id', 'title', 'page_num')

class BookSerializer(serializers.ModelSerializer):
  chapters = ChapterSerializer(many=True)

  class Meta:
    model = Book
    fields = ('id', 'title', 'author', 'chapters')

  def create(validated_data):
    chapters = validated_data.pop('chapters')
    book = Book(**validated_data)
    book.save()
    serializer = ChapterSerializer(data=chapters, many=True)
    if serializer.is_valid(raise_exception=True):
        chapters = serializer.save()

class BookCreate(generics.CreateAPIView):
  serializer = BookSerializer(data=request.data)
  if serializer.is_valid(raise_exception=True):
    serializer.save()
  # Do some other stuff

我发布了一些像这样的JSON:

{
  title: "Test book",
  author: "Test author",
  chapters: [
    {title: "Test chapter 1", page_num: 1},
    {title: "Test chapter 2", page_num: 5}
  ]
}

我收到异常,因为chapter没有book与之关联。如果我将book添加为ChapterSerializer的某个字段,那么JSON将无法验证,因为BookSerializer中的BookCreate无法验证,因为它会预期这些章节的书名,但这本书尚未创建。我该如何解决这种情况?

有没有办法让BookSerializer验证自己的字段,而不是验证其​​chapter

2 个答案:

答案 0 :(得分:4)

您可以在.savepass additional arguments。所以我认为你只需要将新创建的书籍实例传递给serializer,例如

def create(validated_data):
    chapters = validated_data.pop('chapters')
    book = Book(**validated_data)
    book.save()
    serializer = ChapterSerializer(data=chapters, many=True)
    if serializer.is_valid(raise_exception=True):
        chapters = serializer.save(book=book)

答案 1 :(得分:0)

我认为,您不应该在序列化程序的create()方法中创建另一个Serializer,因为这是多余的。如果您将序列化程序定义为此字段引用的模型的序列化程序,则验证已由序列化程序完成:

class BookSerializer(serializers.ModelSerializer):
    # here you define the serializer to validate your input
    chapters = ChapterSerializer(many=True)

相反,您只需创建对象,数据已通过调用初始序列化程序的is_valid()进行验证。无论如何,你需要将书传递给create()方法:

def create(validated_data):
    chapters_data = validated_data.pop('chapters')
    book = Book.objects.create(**validated_data)
    for chapter_data in chapters_data:
        Chapter.objects.create(book=book, **chapter_data)