Django Rest Framework:如何将数据传递给嵌套的序列化程序并仅在自定义验证后创建对象 [英] Django Rest Framework: How to pass data to a nested Serializer and create an object only after custom validation

查看:24
本文介绍了Django Rest Framework:如何将数据传递给嵌套的序列化程序并仅在自定义验证后创建对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个模型:

class Book(AppModel):
    title = models.CharField(max_length=255)

class Link(AppModel):
    link = models.CharField(max_length=255)

class Page(AppModel):
    book= models.ForeignKey("Book", related_name="pages", on_delete=models.CASCADE)
    link = models.ForeignKey("Link", related_name="pages", on_delete=models.CASCADE)
    page_no = models.IntegerField()
    text = models.TextField()

序列化器

class LinkSerializer(serializers.ModelSerializer):
    class Meta:
       model = Link
       fields = ['link']

class PageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Page
        fields = ('link','text','page_no')

    def validate_text(self, value):
        #some validation is done here.

    def validate_link(self, value):
        #some validation is done here.

class BookSerializer(serializers.ModelSerializer):
    pages = PageSerializer(many=True)
    class Meta:
        model = Book
        fields = ('title','pages')

    @transaction.atomic
    def create(self, validated_data):
        pages_data= validated_data.pop('pages')
        book = self.Meta.model.objects.create(**validated_data)
        for page_data in pages_data:
            Page.objects.create(book=book, **page_data)
        return book

PageSerializer 中有一个 validate_text 方法.create 方法永远不会调用 PageSerializer 并且 page_data 永远不会被验证.

There is a validate_text method in PageSerializer. The create method will never call the PageSerializer and the page_data is never validated.

所以我尝试了另一种方法:

So I tried another approach as:

@transaction.atomic
def create(self, validated_data):
    pages_data = validated_data.pop('pages')
    book = self.Meta.model.objects.create(**validated_data)
    for page_data in pages_data:
        page = Page(book=book)
        page_serializer = PageSerializer(page, data = page_data)
        if page_serializer.is_valid():
            page_serializer.save()
        else:
            raise serializers.ValidationError(page_serializer.errors)
    return book

发布的数据:

{
    "title": "Book Title",
    "pages": [
        {
            "link": 1, "page_no": 52, "text": "sometext"
        }
    ]
}

但是上面的方法抛出错误:

But the above approach throws error:

{
    "link": [
        "Incorrect type. Expected pk value, received Link."
    ]
}

我还找到了导致此错误的原因:虽然我使用 pk1Link 发布数据,但数据在传递时从 BookSerializerPageSerializer 出现如下:{link": /go_to_link/", page_no":52,文本":sometext"}

I also found why this error is caused: Though I am posting data with pk value 1 of a Link, the data when passed to the PageSerializer from the BookSerializer appears as such: {"link": "/go_to_link/", "page_no":52, "text": "sometext"}

为什么将Link 的实例传递给PageSerializer 而我发送的是Linkpk?

Why is an instance of Link passed to the PageSerializer whereas what I sent is pk of Link?

推荐答案

使用嵌套序列化程序验证嵌套对象:

To validate a nested object using a nested serializer:

@transaction.atomic
def create(self, validated_data):
    pages_data = validated_data.pop('pages') #pages data of a book
    book= self.Meta.model.objects.create(**validated_data)
    for page_data in pages_data:
        page = Page(book=book)
        page_serializer = PageSerializer(page, data = page_data)
        if page_serializer.is_valid(): #PageSerializer does the validation
            page_serializer.save()
        else:
            raise serializers.ValidationError(page_serializer.errors) #throws errors if any
    return book

假设您将数据发送为:

{
    "title": "Book Title",
    "pages": [{
        "link":2,#<= this one here
        "page_no":52, 
        "text":"sometext"}]
}

在上面的数据中,我们发送了 Link 对象的 id.但是在上面定义的BookSerializercreate方法中,我们发送的数据发生了变化:

In the above data we are sending an id of the Link object. But in the create method of the BookSerializer defined above, the data we sent changes to:

{
    "title": "Book Title",
    "pages": [{
        "link":Link Object (2),#<= changed to the Link object with id 2
        "page_no":52, 
        "text":"sometext"}]
}

PageSerializer 实际上是为了接收 linkpk 值,即 "link": 2 而不是 "link":Link Object (2).因此它抛出错误:

And the PageSerializer is actually meant to receive an pk value of the link i.e, "link": 2 instead of "link":Link Object (2). Hence it throws error:

<代码>{关联": [类型不正确.预期的 pk 值,收到链接."]}

所以解决方法是覆盖嵌套序列化器的to_internal_value方法,将接收到的Link Object (2)对象转换为其pk价值.

So the workaround is to override the to_internal_value method of the nested serializer to convert the received Link Object (2) object to its pk value.

所以你的 PageSerializer 类应该是:

So your PageSerializer class should then be:

class PageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Page
        fields = ('link','text','page_no')

    def to_internal_value(self, data): 
        link_data = data.get("link")
        if isinstance(link_data, Link): #if object is received
            data["link"] = link_data.pk # change to its pk value
        obj = super(PageSerializer, self).to_internal_value(data)
        return obj

    def validate_text(self, value):
        #some validation is done here.

    def validate_link(self, value):
        #some validation is done here.

和父序列化器:

class BookSerializer(serializers.ModelSerializer):
    pages = PageSerializer(many=True)
    class Meta:
        model = Book
        fields = ('title','pages')

    @transaction.atomic
    def create(self, validated_data):
        pages_data = validated_data.pop('pages')#pages data of a book
        book= self.Meta.model.objects.create(**validated_data)
        for page_data in pages_data:
            page = Page(book=book)
            page_serializer = PageSerializer(page, data = page_data)
            if page_serializer.is_valid(): #PageSerializer does the validation
                page_serializer.save()
            else:
                raise serializers.ValidationError(page_serializer.errors) #throws errors if any
        return book

这应该允许嵌套序列化器进行验证,而不是在父序列化器的 create 方法中编写验证并违反 DRY.

That should allow the nested serializer to do the validation instead of writing validation inside the create method of the parent serializer and violating DRY.

这篇关于Django Rest Framework:如何将数据传递给嵌套的序列化程序并仅在自定义验证后创建对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆