Django Rest Framework:如何将数据传递到嵌套序列化器并仅在自定义验证后创建对象

2024-04-27

我有两个模型:

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()

and serializers

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

有一个validate_text中的方法PageSerializer. The create方法永远不会调用PageSerializerpage_data从未被验证过。

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

@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"
        }
    ]
}

但上述方法会引发错误:

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

我还发现了导致此错误的原因:虽然我正在发布数据pk value 1 of a Link,当数据传递到PageSerializer来自BookSerializer看起来像这样:{"link": "/go_to_link/", "page_no":52, "text": "sometext"}

为什么是一个实例Link传递给PageSerializer而我发送的是pk of Link?


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

@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"}]
}

在上面的数据中,我们发送一个id of the Link目的。但在create的方法BookSerializer如上所述,我们发送的数据更改为:

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

And the PageSerializer实际上是为了接收pk的值link i.e, "link": 2代替"link":Link Object (2)。因此它会抛出错误:

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

所以解决方法是覆盖to_internal_value嵌套序列化器的方法来转换接收到的Link Object (2)反对其pk value.

So your PageSerializer那么类应该是:

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。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Django Rest Framework:如何将数据传递到嵌套序列化器并仅在自定义验证后创建对象 的相关文章

随机推荐