DRF多表关联的序列化和反序列化

DRF多表关联的序列化和反序列化

目录

  • DRF多表关联的序列化和反序列化
    • 序列化定制字段source
      • 一对多的序列化
    • 多表关联的序列化
      • 方式1:在表模型中定义方法
      • 方式2:定制返回格式SerializerMethodField
      • 方式3:子序列化
    • 多表关联的反序列化
      • 反序列化保存一对多关联字段
        • create
        • update
      • 反序列化保存多对多关联字段
        • create
    • ModelSerializer类下的序列化和反序列化

序列化定制字段source

# models.py
class Book(models.Model):
    title = models.CharField(max_length=32, null=True)
    price = models.IntegerField(null=True)
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE, null=True)
    author = models.ManyToManyField(to='Author', null=True)
# views.py
class book(APIView):
    def get(self, request):
        book_obj = models.Book.objects.all()
        serializer = BookSerializer(instance=book_obj, many=True)
# serializers.py
class BookSerializer(serializers.Serializer):
	book_name = serializers.CharField(source='title')

这是一个serializers的字段,当我要进行序列化时

  • book_name决定了该字段在前端显示的名字
  • source = 'title'决定了返回给前端的内容是表中的book表中的title字段属性
  • 因此只要source指定了属性值,book_name可以随便改名

一对多的序列化

表中的publish字段

# models.py
class Book(models.Model):
	publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    
class Publish(models.Model):
    name = models.CharField(max_length=32, null=True)
    email = models.EmailField(null=True)

serializers中的序列化

# serializer.py
publish_name = serializers.CharField(source='publish.name')
publish_email = serializers.EmailField(source='publish.email')
  • 当publish是个对象时直接序列化只能打印它的字典对象
  • 因此需要在source中写跨表查询
  • 注意:所有类型都可以用CharField响应

响应结果:

image-20240412215612520

多表关联的序列化

方式1:在表模型中定义方法

# models.py
class Book(models.Model):
    title = models.CharField()
    price = models.IntegerField()
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    author = models.ManyToManyField(to='Author')

    @property
    def publish_detail(self):
        return {'name': self.publish.name, 'email': self.publish.email}
    
    @property
    def author_list(self):
        author_list = []
        for i in self.author.all():
            author_list.append({'name': i.name, 'age': i.age})
        return author_list

class Publish(models.Model):
    name = models.CharField(max_length=32,)
    email = models.EmailField()
# serializers.py
class BookSerializer(serializers.Serializer):
    book_name = serializers.CharField(source='title')
    price = serializers.IntegerField()
    publish_detail = serializers.DictField()
    author_list = serializers.ListField()
  • publish_detail = serializers.DictField()相当于调用了book表中的publish_detail方法,返回的是一个对象

image-20240412223016991

方式2:定制返回格式SerializerMethodField

# models.py
class Book(models.Model):
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE, null=True)
    author = models.ManyToManyField(to='Author', null=True)
# serializers.py
class BookSerializer(serializers.Serializer):
    publish_dict = serializers.SerializerMethodField()

    def get_publish_dict(self, obj):
        return {'name': obj.publish.name, 'email': obj.publish.email}

    author_list = serializers.SerializerMethodField()

    def get_author_list(self, obj):
        author_list = []
        for i in obj.author.all():
            author_list.append({'name': i.name, 'age': i.age})
        return author_list
  • SerializerMethodField():允许你在序列化器中定义一个基于方法的字段
  • 方法名必须是get_ +需要定制的序列化字段
  • obj:相当于将后端定义的表对象传了过来,你可以在里面做跨表查询

方式3:子序列化

# models.py
class Book(models.Model):
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    author = models.ManyToManyField(to='Author')
# serializers.py
class PublishSerializer(serializers.Serializer):
    name = serializers.CharField()
    email = serializers.EmailField()
    
class AuthorSerializer(serializers.Serializer):
    name = serializers.CharField()
    age = serializers.IntegerField()

class BookSerializer(serializers.Serializer):
    publish = PublishSerializer()
    author_detail = AuthorSerializer(source='author', many=True)
  • 直接在serializers中新建PublishSerializer类,让publish字段调用这个类就能获取他的所有属性
  • publishauthor_detail可以任意改名,如果改名的话需要source参数对应表中的字段名,否则会报错
  • 因为author字段是一个列表,所以要在参数中加上many=True

多表关联的反序列化

反序列化保存一对多关联字段

create
# models.py
class Book(models.Model):
    title = models.CharField(max_length=32, null=True)
    price = models.IntegerField(null=True)
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE, null=True)

publish字段一对多关系绑定了Publish表,因此在Book表中显示的是publish_id

image-20240413162012394

在反序列化校验Book对象时,django并不认识Publish表,因此只会识别publish_id,那么前端发送请求时也要传入publish_id

# serializers.py
class BookSerializer(serializers.Serializer):
    book_name = serializers.CharField(source='title')
    price = serializers.IntegerField()
    publish_detail = PublishSerializer(source='publish', read_only=True)

    publish_id = serializers.IntegerField(write_only=True)

    def create(self, validated_data):
        print(validated_data)
        publish_id = validated_data.pop('publish_id')
        book_obj = models.Book.objects.create(**validated_data, publish_id=publish_id)
        return book_obj

在反序列化校验publish_id时为了不影响原先的序列化校验,要在不需要反序列化校验的参数后面加入read_only=True参数,同时publish_id加入write_only参数只作用于反序列化校验

  • read_only=True:该字段只会用于序列化校验
  • write_only=True:该字段只会用于反序列化校验

重写create方法(重点

  • 此时前端传入的参数应为:
    image-20240413163621635

  • print(validated_data)打印结果为:

    {'title': '三体', 'price': 900, 'publish_id': 2}
    
  • 先不看代码来试一下,如果这是我直接book_obj = models.Book.objects.create(**validated_data)会发生什么?

book_obj = models.Book.objects.create(**validated_data)
print(book_obj.publish_id)
# 结果:None
  • 这是因为,虽然validated_data包含了publish_id字段,但是此时它并不具备外键属性,Django仅将他作为一个普通字段进行反序列化

  • 那么理所当然的后端的序列化结果也不会成功,因为publish_detail是根据外键属性取值的

  • 所以此时这里应该明确用publish_id作为publish_id字段的参数

# 先将publish_id参数从vaildated_data中踢出,让前两个参数以**方式传入后再指定publish_id
publish_id = validated_data.pop('publish_id')

# 左边的publish_id是字段,右边的publish_id是前端传来的数据
book_obj = models.Book.objects.create(**validated_data, publish_id=publish_id)

# 这种方法和上面的含义相同,用其中一种即可
book_obj = models.Book.objects.create(title=validated_data.get('title'), price=validated_data.get('price'), publish_id=publish_id)

image-20240413165250525

  • 传入成功应正确返回序列化后的字段
update
# views.py
def put(self, request, u_id):
    book_obj = models.Book.objects.filter(pk=u_id).first()
    # 改对象必须传data和instance
    serializer = BookSerializer(instance=book_obj, data=request.data)
    if serializer.is_valid():
        serializer.save()
        return Response({'code': '200', 'msg': "修改成功", 'result': serializer.data})
    else:
        return Response({'code': '201', 'msg': serializer.errors})
# serializers.py
def update(self, instance, validated_data):
    instance.publish_id = validated_data.get('publish_id')
	instance.title = validated_data.get('title')
    instance.price = validated_data.get('price')
    instance.save()

    return instance
  • updata相比于create就多了个instance参数
  • instance就是views层传过来的模型对象,将要修改的字段保存为validated_data中的数据即可

反序列化保存多对多关联字段

create

首先定义一个author字段,与Author表绑定多对多关系字段

class Book(models.Model):
    title = models.CharField(max_length=32, null=True)
    price = models.IntegerField(null=True)
    author = models.ManyToManyField(to='Author', null=True)

class Author(models.Model):
    name = models.CharField(max_length=10, null=True)
    age = models.SmallIntegerField(null=True)

那么此时的数据便不会存在于BookAuthor中,而是自动新建一个book_author表,例如:

image-20240413183246545

def create(self, validated_data):
    author_id = validated_data.pop('author_id')
    book_obj = models.Book.objects.create(**validated_data)
    book_obj.author.add(author_id)
    return book_obj
  • 首先将author_id踢出,然后将其单独插入中间表book_author,具体原因跟一对多关系相同

ModelSerializer类下的序列化和反序列化

# models.py
class Author(models.Model):
    name = models.CharField(max_length=10, null=True)
    age = models.SmallIntegerField(null=True)
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE, null=True)
# views.py
class author(APIView):
    def get(self, request):
        author_obj = models.Author.objects.all()
        serializer = AuthorSerializer(instance=author_obj, many=True)
        return Response({'code': '200', 'msg': '查询成功', 'result': serializer.data})
# serializer.py
from app.models import Author

class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'
        extra_kwargs = {
            'name': {'max_length': 8},  # 限制name不能超过8
            'author_detail': {'read_only': True},
        }

  • 此时序列化类中就不需要一个个写字段了,ModelSerializer会自动跟表做对应关系
  • model:需要对应的表
  • fields:用于指定需要被序列化的字段,'__all__'为全部['name', 'age']为指定
  • extra_kwargs:类似钩子函数,将对应字段加上限制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/541011.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java---搭建junit4.x单元测试环境,并进行测试

搭建junit4.x单元测试环境 1.选择Project Structure 2.选择Modules,选择要加入测试环境的模块,选择Dependencies,可以看到当前模块都有哪些依赖。 3.点击 后选择第一个 4.找到你安装IDEA的文件夹,进入到IntelliJ IDEA 2018.3.4\lib目录下…

桥接模式:解耦抽象与实现的设计艺术

在软件设计中,桥接模式是一种结构型设计模式,旨在将抽象部分与其实现部分分离,使它们可以独立地变化。这种模式通过提供更加灵活的代码结构帮助软件开发人员处理不断变化的需求,特别是在涉及多平台应用开发时。本文将详细介绍桥接…

规则引擎之LiteFlow应用

官网地址&#xff1a;LiteFlow DEMO 整体结构 1.引入maven依赖 <dependency><groupId>com.yomahub</groupId><artifactId>liteflow-spring-boot-starter</artifactId><version>2.11.4.2</version> </dependency> 2. 配置yml …

Visual Studio code无法正常执行Executing task: pnpm run docs:dev

最近尝试调试一个开源的项目&#xff0c;发现cmd可以正常启动&#xff0c;但是在vs中会报错&#xff0c;报错内容如下 Executing task: pnpm run docs:dev pnpm : 无法加载文件 E:\XXXX\pnpm.ps1&#xff0c;因为在此系统上禁止运行脚本。有关详细信息&#xff0c;请参阅 http…

jmeter实验 模拟:从CSV数据到加密请求到解密返回数据再到跨越线程组访问解密后的数据

注意,本实验所说的加密只是模拟加密解密,您需要届时写自己的加解密算法或者引用含有加密算法的相关jar包才行. 思路: 线程组1: 1.从CSV文件读取原始数据 2.将读取到的数据用BeanShell预习处理器进行加密 3.HTTP提取器使用加密后的数据发起请求 4.使用BeanShell后置处理器…

外贸公司应该怎么选择企业邮箱?哪个企业邮箱最好?

外贸公司业务的特殊性需要他们频繁进行跨国的沟通交流&#xff0c;那么外贸公司应该如何选择适合的企业邮箱呢&#xff1f;首先&#xff0c;传输邮件的稳定安全是前提&#xff0c;另外由于沟通多是国外客户&#xff0c;邮件的翻译也成为外贸公司企业邮箱的刚需。小编今天就详细…

怎么用Vivado做覆盖率分析

关注公众号FPGA开源工坊获取更多内容。 在做仿真的时候往往会去做代码覆盖率和功能覆盖率的分析&#xff0c;来保证仿真是做的比较充分完备的。 在Vivado里面也支持我们做这项操作&#xff0c;现在就来看一下流程吧。 第一步&#xff1a;选择设置 第二步&#xff1a;在仿真选…

每日一题---OJ题: 环形链表 II

片头 嗨! 小伙伴们,大家好! 我们又见面啦,在上一篇中,我们学习了环形链表I, 今天我们继续来打boss,准备好了吗? Ready Go ! ! ! emmm,同样都是环形链表,有什么不一样的地方呢? 肯定有, 要不然也不会一个标记为"简单" ,一个标记为"中等"了,哈哈哈哈哈 …

《AI创业浪潮:展望未来,解锁颠覆性创新机遇》

在科技革命的浪潮中&#xff0c;人工智能&#xff08;AI&#xff09;犹如一艘引领航向的旗舰&#xff0c;以其强大的变革力量重塑各行各业。随着技术的日益成熟与应用场景的不断拓宽&#xff0c;AI技术为创业者铺就了一条充满机遇与挑战的道路。本文将深入探讨未来AI技术领域的…

1.3 字符设备驱动

1、字符设备驱动工作原理 2、file_operations结构体 struct file_operations { struct module *owner; //拥有该结构的模块的指针&#xff0c;一般为THIS_MODULES loff_t (*llseek) (struct file *, lof…

10 Php学习:循环

在 PHP 中&#xff0c;提供了下列循环语句&#xff1a; while - 只要指定的条件成立&#xff0c;则循环执行代码块do…while - 首先执行一次代码块&#xff0c;然后在指定的条件成立时重复这个循环for - 循环执行代码块指定的次数foreach - 根据数组中每个元素来循环代码块 当…

(学习日记)2024.04.15:UCOSIII第四十三节:任务消息队列

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

橱窗带货真的能赚到钱吗?橱窗带货素材哪里找?什么是橱窗带货?

什么是橱窗带货&#xff1f; 橱窗带货&#xff0c;一种以货架电商为基础的营销手段&#xff0c;可类比线下实体店的展示柜和窗口。橱窗的曝光量较高&#xff0c;因此通常展示店铺中的重点产品和推荐系列商品。短视频已经积极进军电商领域&#xff0c;虽然一开始主打直播电商&a…

newman下载安装

postman是专为接口测试而生&#xff0c;Newman是专为postman而生。newman可以让我们的postman的脚本通过非GUI(命令行)的方式。 1. 安装node.js 安装步骤 查看已安装版本 node -v 2. 安装 Newman 运行命令:npm install -g newman&#xff0c;即可完成安装操作。 或者 npm i…

(Oracle)SQL优化案例:隐式转换优化

项目场景 项目现场的某个kettle模型执行非常缓慢&#xff0c;原因在于某个SQL执行效率非常的低。甲方得知此事要求公司赶紧优化&#xff0c;负责该模块的同事对SQL优化并不熟悉。所以作为一个立志成为优秀DBA的ETL工程师&#xff0c;我自告奋勇&#xff1a;不是DBA&#xff0c;…

两步解决 Flutter Your project requires a newer version of the Kotlin Gradle plugin

在开发Flutter项目的时候,遇到这个问题Flutter Your project requires a newer version of the Kotlin Gradle plugin 解决方案分两步: 1、在android/build.gradle里配置最新版本的kotlin 根据提示的kotlin官方网站搜到了Kotlin的最新版本是1.9.23,如下图所示: 同时在Ko…

人事|基于SpringBoot+vue的人事管理系统设计与实现(源码+数据库+文档)

人事管理系统目录 基于SpringBootvue的人事管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&#xff0c;…

链表中常见的使用方法逻辑整理

文章目录 1. 链表特点2. 链表创建3. 链表遍历通用方法3.1 在链表的开头添加元素3.2 在链表的结尾添加元素3.3 删除链表的第一个元素3.4 删除链表的最后一个元素3.5 遍历链表3.6 查找链表中的元素3.7 反转链表 4. 常见面试题4.1 相交链表4.2 反转链表4.3 环形链表4.4 环形链表 I…

Nacos-默认token.secret.key-配置不当权限绕过漏洞复现

漏洞描述&#xff1a; Nacos 身份认证绕过漏洞(QVD-2023-6271)&#xff0c;开源服务管理平台 Nacos在默认配置下未对 token.secret.key 进行修改&#xff0c;导致远程攻击者可以绕过密钥认证进入后台&#xff0c;造成系统受控等后果。 漏洞信息 公开时间&#xff1a;2023-03…

Windows安装MongoDB结合内网穿透轻松实现公网访问本地数据库

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…