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:如何将数据传递到嵌套序列化器并仅在自定义验证后创建对象 的相关文章

  • HTML 嵌入对象具有灰色背景。可以透明吗?

    我使用带有开源插件的 Firefox 来播放视频 视频被 尽可能好地 缩放以适应嵌入对象的宽度和高度中定义的可用空间 但有时右侧和 或底部会有一点灰色边框 看来这不是我的父 div 的背景颜色 因为更改它根本没有效果 这是 HTML div
  • Xcode 6.4 Swift 单元测试无法编译:“GPUImage.h 未找到”“无法导入桥接标头”

    我的 Xcode 项目构建并运行良好 它有 Swift 和 Objective C 代码 它已安装 GPUImage 我向它添加了单元测试 现在它将不再编译 找不到 GPUImage h 文件 导入桥接标头失败 以下是我发现并尝试过的解决方
  • 跨延迟加载路由创建共享模块

    我正在构建一个 Angular 11 应用程序并尝试创建一个SharedModule 我正在使用延迟加载 并希望避免在延迟加载的路由中多次加载公共模块 我创建了一个共享模块并将其导入到我的AppModule 根据我的理解 这个共享模块应该在
  • 按列分组的数据帧上 R 中的行之间的差异

    我希望通过 app name 获得不同版本的计数差异 我的数据集如下所示 app name version id count difference 这是数据集 data structure list app name structure c
  • 如何防止 Safari 滚动溢出:隐藏的 iframe?

    使用 Safari 您可以通过设置 style overflow hide 来禁用大多数 iframe 滚动 在 iframe 上 但是 如果您单击 iframe 并移动鼠标 内容无论如何都会滚动 Example 滚动内容 html
  • 使用 AWS MSK 连接器连接到 AWS VPC 内的 MongoDB atlas

    我正在尝试使用MongoDB使用更改流Kafka 我选择 AWS MSK 是因为我的整个基础设施都位于 AWS 内 并且可以轻松与其他 AWS 服务集成 I created an AWS MSK cluster within the VPC
  • d3.js 更新视觉效果

    我有一个与 d3 js 放在一起的树形图 我通过 getJSON 填充数据 效果很好 但是 我在 setInterval 方法中具有此功能 并且它似乎并没有刷新自身 var treemap d3 layout treemap padding
  • 安装 APK 时出现会话“应用程序”错误

    我在将 Android Studio 1 1 编写的项目导入 Android Studio 2 1 2 时遇到困难 每当在平板电脑上测试应用程序之前构建 gradle 时 我都会收到此错误 下面是错误的屏幕截图 有谁知道是什么问题 我尝试过
  • 为什么我们不能在函数式接口中重载抽象方法? (爪哇)

    所以我熟悉java中的函数式接口 以及它们与lambda表达式的使用 一个函数式接口只能包含一个抽象方法 当从 lambda 表达式使用这一孤独方法时 您不需要指定其名称 因为接口中只有一个抽象方法 编译器知道这就是您正在引用的方法 Exa
  • 使用 wmi 获取活动会话(Win32_LogonSession 还返回非活动/旧会话)

    有没有办法只显示 wmi 的活动会话 问题是 Win32 LogonSession 还显示不活动 断开连接的会话 ManagementScope scope new ManagementScope ManagementPath Defaul
  • 如何在Asp.Net Core中自定义开发者异常页面?

    这常见于ConfigureStartup cs 文件的方法具有如下所示的代码 if env IsDevelopment app UseDeveloperExceptionPage new DeveloperExceptionPageOpti
  • 从基元创建自定义形状

    我正在尝试通过组合原始形状来创建自定义物理形状 目标是创建一个圆形立方体 合适的方法似乎是初始化 形状 变换 我在这里找到的https developer apple com library prerelease ios documenta
  • DELPHI 和 WANT 或 NANT

    We use 巡航控制 net http confluence public thoughtworks org display CCNET Welcome to CruiseControl NET在 Delphi 2006 应用程序中进行持
  • 重定向到破折号中的 url

    我正在使用 dash 构建一个仪表板 每当单击特定数据点时 我都会创建一个唯一的 url 如何将用户重定向到此创建的 url 我正在使用下面给出的代码 每当有人单击任何数据点时 单击事件就会触发并执行回调函数 app layout html
  • 扁平化/反规范化 SQL 查找表的最佳方法?

    我有很多这样的表 Lookup HealthCheckupRisks ID Name 1 Anemia 2 Anorexic 3 Bulemic 4 Depression 122 Syphilis PatientRisksOnCheckup
  • 如何将 c_uint 的 ctypes 数组转换为 numpy 数组

    我有以下 ctypes 数组 data ctypes c uint 100 我想创建一个 numpy 数组np data包含来自 ctypes 数组数据的整数值 ctypes 数组显然稍后会填充值 我看到numpy中有一个ctypes接口
  • 如何使用 Spark 2 屏蔽列?

    我有一些表 我需要屏蔽其中的一些列 要屏蔽的列因表而异 我正在读取这些列application conf file 例如 对于员工表如下所示 id name age address 1 abcd 21 India 2 qazx 42 Ger
  • 如何通过API集成keycloak短信验证?

    我有一个 keycloak 服务器和使用自定义 KeycloakProvider 的 Laravel 应用程序 public function loginByEmail string email string password SsoTok
  • 你将如何开始自动化我的工作? - 第2部分

    后续这个问题 https stackoverflow com questions 2796128 how would you start automating my job 在经历了第一波进货 9 小时的复制 粘贴 后 我现在相信我已经满足
  • KIOSK 系统的一台 PC 上有多个显示器

    我正在使用 PHP HTML5 和 Javascript 开发 KIOSK 系统 我想在一台 PC 上连接多个 触摸屏 显示器 我希望这些监视器以全屏模式显示浏览器 用户只能访问 我的网站 而无需任何其他控件 他们不会有鼠标或键盘 他们不应

随机推荐