rest_framework(4)序列化和反序列化(二)

本系列文章中的上一篇文章:序列化和反序列化(一)

urls.py 代码

from django.urls import re_path
from sers.views import BookDetailView
urlpatterns = [re_path(r"sers/book/(\d+)", BookDetailView.as_view()),
}

models.py 代码

from django.db import models# Create your models here.
class Book(models.Model):title = models.CharField(max_length=32, verbose_name="书籍名称")price = models.IntegerField(verbose_name="价格")pub_date = models.DateField(verbose_name="出版日期")

views.py 代码

导入的包

from rest_framework.views import APIView
from rest_framework import serializers
from rest_framework.response import Response
from sers.models import Book

BookSerializer 类

# 定义序列化器
# 一个序列化类是针对某个模型(数据库表)进行设计的
class BookSerializer(serializers.Serializer):# 这些字段对应着数据库表的字段和类型# CharField、IntegerField、DateField 在反序列化的时候校验数据用的# 比如 title 要求是字符串,且长度要求不超过 32 位title = serializers.CharField(max_length=32)price = serializers.IntegerField()# pub_date = serializers.DateField()# 如果想序列化后的键的名字自定义# 则要指定 source="pub_date" 参数,对应数据库里的字段名date = serializers.DateField(source="pub_date")# 重写父类中的 create 方法,实现自己的数据保存逻辑# create 方法需要返回值,因为在源码中 save 方法需要接收 create 方法的返回值def create(self, validated_data):new_book = Book.objects.create(**validated_data)return new_book# 重写父类中的 update 方法,实现更新数据逻辑# update 方法需要返回值,因为在源码中 save 方法需要接收 create 方法的返回值def update(self, instance, validated_data):Book.objects.filter(pk=instance.pk).update(**validated_data)update_book = Book.objects.get(pk=instance.pk)return update_book

BookDetailView 类

class BookDetailView(APIView):# 查找单个书籍对象def get(self, request, id):book = Book.objects.get(pk=id)# 构建序列化器对象# 进行序列化处理,返回给前端 JSON 格式数据# 默认 many=False,表示对一个对象序列化,而不是对多个对象# 得到的 JSON 格式就是一个 {} 的对象形式,而不是一个列表 [{}, {}, ...]# 这就是 many 参数的作用serializer = BookSerializer(instance=book, many=False)"""serializer.data 时发生以下动作:t = {}# BookSerializer 类中有几个字段,字典 t 中就会有几个键值对# BookSerializer 类中的字段名要和数据库表字段一样# 否则 obj.title 获取值的时候就会出错t["title"] = obj.titlet["price"] = obj.price# 除非自定义了名字:date = serializers.DateField(source="pub_date")# t["pub_date"] = obj.pub_datet["date"] = obj.datereturn t"""return Response(serializer.date)# 更新部分书籍信息def put(self, request, id):# 获取提交的更新后的数据print(request.data)# 获取更新前的对象book = Book.objects.get(pk=id)# 构建序列化器对象# 传入 instance 和 data 两个关键字参数# 之所以两个都需要,是因为需要在对象原基础上进行更新,即只更新改变的部分# 需要传 instance 是因为在调用 save 方法的时候需要判断是添加还是更新,具体参照源码serializer = BookSerializer(instance=book, data=request.data)# 对提交的更新后的数据进行校验if serializer.is_valid():# # 数据合法,进行更新# Book.objects.filter(pk=id).updata(**serializer.validated_data)# # 获取更新之后的书籍信息# update_book = Book.objects.get(pk=id)# serializer.instance = update_book# 把更新的逻辑抽取出来# 提取出来的逻辑都在 update 方法中,详细参见 save 源码,如下"""serializer.save() 的源码1、先看序列化器 BookSerializer ,类中没有 save() 方法,class BookSerializer(serializers.Serializer):# ...# 重写父类中的 create 方法,实现更新数据逻辑def create(self, validated_data):# ...# 重写父类中的 update 方法,实现更新数据逻辑# update 方法需要返回值,因为在源码中 save 方法需要接收 create 方法的返回值def update(self, instance, validated_data):Book.objects.filter(pk=instance.pk).update(**validated_data)update_book = Book.objects.get(pk=instance.pk)return update_book2、再找 BookSerializer 的父类 Serializer,也没有 save() 方法class Serializer(BaseSerializer, metaclass=SerializerMetaclass):# ...3、再找 Serializer 的父类 BaseSerializer,找到了 save() 方法class BaseSerializer(Field):# update 和 create 方法中什么都没做,而是直接抛出了异常,这样做的目的就是为了让子类重写该方法def update(self, instance, validated_data):raise NotImplementedError('`update()` must be implemented.')def create(self, validated_data):raise NotImplementedError('`create()` must be implemented.')def save(self, **kwargs):# ...# 此时 self 指的是 BookSerializer 的实例对象 serializer# instance 表示的是要序列化的数据# instance 不为空,所以走的是 if 中的代码# 更正一下上一篇文章中关于 save 方法源码的说法# 当序列化器实例对象中有 instance 属性时,即在构建序列化器对象时传入 instance 参数# 就会走 if 中的代码,那么当调用 save 方法时,就是更新数据# 而如果 instance 为空,即没有传递,则走的是 else 中的代码# 此时调用 save 方法就是向数据库插入一条新的数据# create 和 update 方法都需要在子类中重写# 以根据实际的添加和更新逻辑进行操作if self.instance is not None:self.instance = self.update(self.instance, validated_data)assert self.instance is not None, ('`update()` did not return an object instance.')else:# self.create() 方法的查找:通过一层层的查找最后也是在 BaseSerializer 类中找到了self.instance = self.create(validated_data)assert self.instance is not None, ('`create()` did not return an object instance.')# 返回的 instance 用于序列化的时候使用,具体见 serializer.data 的源码return self.instance"""serializer.save()"""serializer.date 的源码解析:data 实际上是一个方法,因为该方法上加了 @property,所以可以不加小括号进行调用还是按照继承的类对 data 进行查找1、先查找 BookSerializer 类,没有2、查找 BookSerializer 的父类 serializers.Serializer,找到了其中 ret = super().data 调用的是 Serializer 的父类 BaseSerializer 中的 data@propertydef data(self):# 通过以下的源码可知 ret = self.instance 序列化后的结果ret = super().datareturn ReturnDict(ret, serializer=self)3、BaseSerializer 的 data 源码@propertydef data(self):# ...# self 指的是 serializer # 如果 self 没有 _data 属性,即没有进行序列化if not hasattr(self, '_data'):# 如果 self 有 instance 属性# 并且 self._errors 为 None,即数据都合法,没有错误信息if self.instance is not None and not getattr(self, '_errors', None):# 使用 to_representation 方法对 instance 进行序列化处理# 并将处理结果,即序列化后的数据赋值给 _data # to_representation 的处理逻辑就是上一篇文章提到的 temp = []; for ... in book_listself._data = self.to_representation(self.instance)elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):self._data = self.to_representation(self.validated_data)else:self._data = self.get_initial()# 返回序列化的结果return self._data"""return Response(serializer.date)else:return Response(serializer.errors)def delete(self, request, id):Book.objects.get(pk=id).delete()return Response()

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【⑬MySQL | 数据类型(一)】简介 | 整数 | 浮点 | 定点类型

前言 ✨欢迎来到小K的MySQL专栏,本节将为大家带来MySQL数据类型简介 | 整数 | 浮点 | 定点类型的分享✨ 目录 前言0.数据类型简介1 整数类型2 浮点类型3 定点类型4 日期/时间类型总结 0.数据类型简介 数据类型(data_type)是指系统中所允许的…

LRU淘汰策略执行过程

1 介绍 Redis无论是惰性删除还是定期删除,都可能存在删除不尽的情况,无法删除完全,比如每次删除完过期的 key 还是超过 25%,且这些 key 再也不会被客户端访问。 这样的话,定期删除和堕性删除可能都彻底的清理掉。如果…

百度许少辉著Baidu《乡村振兴战略下传统村落文化旅游设计》图书馆新书通报

百度许少辉著Baidu《乡村振兴战略下传统村落文化旅游设计》图书馆新书通报

docker保存容器镜像并在新机器加载

保存镜像,主要用到 docker save命令 从镜像包加载镜像,主要用到 docker load命令 目录 方法1 多个镜像,且带额外操作,如压缩的情况 方法2 方法1 docker save 0fk8ab59a85f > im.tar 或 docker save 镜像名称:tag > im…

AWS SDK 3.x for .NET Framework 4.0 可行性测试

前言 为了应对日益增长的网络安全挑战, 越来越多的互联网厂商已经陆续开始或者已经彻底停止了对 SSL 3 / TLS 1.0 / TLS1.1 等上古加密算法的支持. 而对于一些同样拥有悠久历史的和 AWS 服务相关联的应用程序, 是否可以通过仅更新 SDK 版本的方式来适应新的环境. 本文将以 Win…

揭开pkill的秘密:在Linux中杀死进程的完整指南

揭开pkill的秘密:在Linux中杀死进程的完整指南 一、前言二、进程管理基础知识2.1、什么是进程?2.2、进程管理的原理和目的2.3、进程状态和标识符 三、理解Linux pkill命令3.1、pkill命令的概述和作用3.2、与kill命令的对比3.3、常见的pkill命令选项和参数…

Linux 编译内核模块出现--Unknown symbol mcount

文章目录 Linux suse: # cat /etc/os-release NAME"SLES" VERSION"12-SP2" VERSION_ID"12.2" PRETTY_NAME"SUSE Linux Enterprise Server 12 SP2" ID"sles" ANSI_COLOR"0;32" CPE_NAME"cpe:/o:s…

PCAP01介绍和STM32模拟SPI驱动

一.芯片介绍 Pcap01是德国acam公司设计的一款革命性的电容测量芯片。该芯片 内部有DSP计算单元,可以直接将电容元件接到Pcap01芯片,然后芯片计算出容值大小,通过SPI总线将电容容值数据传送给CPU,电容测量完全数字化。 二,测量原…

LeetCode 面试题 01.05. 一次编辑

文章目录 一、题目二、C# 题解法一:从第一个不同位置处判断后续相同子串法二:前后序遍历判断第一个不同字符的位置关系 优化法一法二 一、题目 字符串有三种编辑操作:插入一个英文字符、删除一个英文字符或者替换一个英文字符。 给定两个字符串&#xff…

无脑入门pytorch系列(五)—— nn.Dropout

本系列教程适用于没有任何pytorch的同学(简单的python语法还是要的),从代码的表层出发挖掘代码的深层含义,理解具体的意思和内涵。pytorch的很多函数看着非常简单,但是其中包含了很多内容,不了解其中的意思…

docker启用cgroup v2

要求 本人的操作系统是kali,基于debian docker info如果你这里是2那么说明启用了,如果是1,那么就未启用 对于Docker来说,Cgroups v2的使用需要满足以下条件: Linux内核版本在4.15以上。 uname -r 系统已经启用Cgro…

前端处理图片文件的方法

在项目开发过程中&#xff0c;有一个需求&#xff0c;需要前端对上传的图片进行处理&#xff0c;以字符串的形式传给后端&#xff0c;实现效果如下&#xff1a; 1.上传图片的组件 在该项目中&#xff0c;使用了element plus组件库 <el-uploadv-model:file-list"fileL…

c++(8.23)类,this指针,构造函数,析构函数,拷贝构造函数

设计一个Per类&#xff0c;类中包含私有成员&#xff1a;姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员&#xff1a;成绩、Per类对象 p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 #include <iostream>u…

Java中static的应用之单例模式

单例模式是一种创建对象的设计模式&#xff0c;它保证一个类只有一个实例&#xff0c;并提供一个全局访问点。由于单例模式只允许存在一个实例&#xff0c;因此它可以节省系统资源并提高程序的性能。在许多情况下&#xff0c;单例模式在应用程序中都是非常有用的&#xff0c;例…

Linux——Shell常用运算符

运算符说明举例-eq检测两个数是否相等&#xff0c;相等返回 true。[ $a -eq $b ] 返回 false。-ne检测两个数是否不相等&#xff0c;不相等返回 true。[ $a -ne $b ] 返回 true。-gt检测左边的数是否大于右边的&#xff0c;如果是&#xff0c;则返回 true。[ $a -gt $b ] 返回 …

​8th参考文献:[8]许少辉.乡村振兴战略下传统村落文化旅游设计[M]北京:中国建筑工业出版社,2022.

​&#xff18;th参考文献&#xff1a;&#xff3b;&#xff18;&#xff3d;许少辉&#xff0e;乡村振兴战略下传统村落文化旅游设计&#xff3b;&#xff2d;&#xff3d;北京&#xff1a;中国建筑工业出版社&#xff0c;&#xff12;&#xff10;&#xff12;&#xff12;&a…

notebook写好代码后直接生成PPT报告(html格式)

注&#xff1a;记录使用notebook直接生成html格式的PPT报告&#xff08;html格式&#xff09;。 前置内容&#xff1a;如果直接导出没有Reveal.js.slides(.slides.html)选项&#xff0c;需要安装插件nbextensions。 安装参考&#xff1a;插件nbextensions安装 操作步骤&#x…

力扣题解(1051. 高度检查器),带注释

题目描述 链接:点我 题解 class Solution {public int heightChecker(int[] heights) {//法一 直接排序比较// int[] temp new int[heights.length];// for(int i0;i<heights.length;i)// temp[i] heights[i];// Arrays.sort(temp);// int ans 0;// for(int i0;…

前端面试的计算机网络部分(2)每天10个小知识点

目录 系列文章目录前端面试的计算机网络部分&#xff08;1&#xff09;每天10个小知识点 知识点11. DNS 完整的查询过程递归查询过程&#xff1a;迭代查询过程&#xff1a; 12. OSI 七层模型13. TCP 的三次握手和四次挥手三次握手&#xff08;Three-Way Handshake&#xff09;&…

PostgreSQL-UDF用户自定义函数-扩展插件

目录 PostgreSQL-UDF用户自定义函数-扩展插件零、前置条件一、创建 .c 和 .sql 文件创建.c文件创建.sql文件 二、创建 .control 和 Makefile 文件创建 .control 文件创建 Makefile 文件 三、编译 & 链接四、psql&#xff08;或者其他PG backend&#xff09;中创建扩展 Post…