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

查看:56
本文介绍了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)
链接= models.ForeignKey( Link,related_name = pages,on_delete = models.CASCADE)
page_no = models.IntegerField()
text = models.TextField()

serializers

  class LinkSerializer(serializers.ModelSerializer):
类Meta:
模型=链接
字段= ['link']

类PageSerializer(serializers.ModelSerializer):
类Meta:
模型=页面
字段=('link','text','page_no')

def validate_text(self,value):
#一些验证在这里完成。

def validate_link(self,value):
#一些验证在这里完成。

类BookSerializer(serializers.ModelSerializer):
页= PageSerializer(很多=真)
类元:
模型=书籍
字段=(' title','pages')

@ transaction.atomic
def create(self,validated_data):
pages_data = validated_data.pop('pages')
书= self.Meta.model.objects.create(** validated_data)
用于pages_data中的page_data:
Page.objects.create(book = book,** page_data)
返回书

<$ c $中有一个 validate_text 方法c> PageSerializer 。 create 方法将永远不会调用 PageSerializer page_data



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

  @ transaction.atomic 
def create(self,validated_data):
pages_data = validated_data.pop('pages')
book = self.Meta.model.objects.create(** validated_data)
用于pages_data中的page_data:
page = Page(book = book)
page_serializer = PageSerializer(page,data = page_data)
如果page_serializer.is_valid():
page_serializer.save()
其他:
提高serializers.ValidationError(page_serializer.errors)
返回书

发布的数据:

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

但是上述方法会引发错误:

  {
link:[
类型错误。预期的pk值,已收到链接。
]
}

我也找到了为什么导致此错误:尽管我发布的数据是 pk 1 Link ,当数据从 BookSerializer 传递到 PageSerializer 时,显示如下: { link: / go_to_link /, page_no:52, text: sometext}



为什么将 Link 的实例传递给 PageSerializer ,而我发送的却是 pk Link ?需要帮助。

解决方案

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

  @ transaction.atomic 
def create(self,validated_data) :
pages_data = validated_data.pop('pages')#一本书的页面数据
book = self.Meta.model.objects.create(** validated_data)
用于pages_data中的page_data:
页面=页面(book = book)
page_serializer = PageSerializer(page,data = page_data)
如果page_serializer.is_valid():#PageSerializer进行验证
page_serializer.save()
否则:
引发serializers.ValidationError(page_serializer .errors)#如果有任何
归还书

,则抛出错误假设您将数据发送为:

  {
title:书名,
页面:[{
link:2,#< =这里的这个
page_no:52,
text: sometext}]
}

在上述数据中,我们发送了<$ c $的 id c>链接对象。但是在上面定义的 BookSerializer create 方法中,我们发送的数据更改为:

  {
title:书名,
页面:[{
link:链接对象(2),#< =更改为ID为2的链接对象
page_no:52,
text: sometext}]
}

PageSerializer 实际上是为了接收<$ c 链接的$ c> pk 值,即 link:2 链接:链接对象(2)。因此它会引发错误:



{
link:[
类型错误。预期的pk值,已收到链接。
]
}



因此,解决方法是覆盖 to_internal_value 方法将接收到的链接对象(2)对象转换为其 pk 值。 / p>

因此,您的 PageSerializer 类应为:

  class PageSerializer(serializers.ModelSerializer):
类元:
模型=页面
字段=('link','text','page_no')

def to_internal_value(self,data):
link_data = data.get( link)
if isinstance(link_data,Link):#如果接收到对象
data [ link] = link_data.pk#更改为其pk值
obj = super(PageSerializer,self).to_internal_value(data)
return obj

def validate_text (自我,价值):
#一些验证在这里完成。

def validate_link(self,value):
#一些验证在这里完成。

和父级序列化器:

  class BookSerializer(serializers.ModelSerializer):
页= PageSerializer(很多=真)
类元:
模型=图书
字段=(' title','pages')

@ transaction.atomic
def create(self,validated_data):
pages_data = validated_data.pop('pages')#a的页面数据book
book = self.Meta.model.objects.create(** validated_data)
用于pages_data中的page_data:
page = Page(book = book)
page_serializer = PageSerializer( page,data = page_data)
如果page_serializer.is_valid():#PageSerializer进行验证
page_serializer.save()
否则:
引发serializers.ValidationError(page_serializer.errors) #如果有任何
归还书

,则会引发错误,这应该允许嵌套的序列化程序进行验证,而不是在父序列化器的create方法内部编写验证并违反DRY。


I have two models as:

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

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

Posted data:

{
"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."
    ]
}

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

Why is an Instance of Link passed to the PageSerializer whereas what I sent is pk of Link? NEED hELP HERE.

解决方案

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

Suppose you send the data as:

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

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

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:

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

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.

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.

and the parent serializer:

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

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天全站免登陆