DRF 序列化组件 序列化的两种方式 反序列化 反序列化的校验
序列化组件 |
django自带的有序列化组件不过不可控不建议使用(了解)
from django.core import serializers class Books(APIView):
def get(self,request):
response = {'code':100,'msg':'查询成功'}
books = models.Book.objects.all()
# 了解django自带的序列化组件
ret= serializers.serialize("json",books)
return HttpResponse(ret)
使用drf的序列化组件
自定义py文件里为了和view视图函数隔离开 自定义文件中写serializer组件
1 新建一个序列化类继承Serializer 2 在类中写序列化的字段
source='表中字段' 自定义的字段不能和表中的字段名一样 username=serializer.CharField(source='name') username自定义的字段 source指定的是表中的字段
要序列化的对象默认传给instance 视图函数中的instance可以不写
source可以写跨表字段'publish.name' 之前跨表是book.publish.name 现在用source就可以省略book了 写成publish.name
source不但可以指定一个字段 还可以指定一个方法
#自定义的py文件中 from rest_framework import serializers #序列化组件 class BookSerializer(serializers.Serializer):
# 指定source = 'name' 表示序列化模型表中的name字段 重命名为name5(name5这个字段名 和source=’name'指定的模型表中的name字段名不能一样)
name5 = serializers.CharField(source='name')
# write_only 序列化的时候,该字段前端不显示
# read_only 反序列化的时候,该字段不传 前端传过来的时候可以不传参数或者字段
price = serializers.CharField(write_only=True) #如果要取 出版社的city 之前跨表查询是 book.publish.city 现在 source = 'publish.city' 不需要点击本身这张表的字段了
# source的值传给了默认形参instance
publish = serializers.CharField(source='publish.name') #出版社名字 #source不但可以指定一个字段,还可以指定一个方法 自定义choices字段取值固定用法get_字段_display
book_type = serializers.CharField(source='get_category_display',read_only=True)
#model.py模型表
class Book(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
category = models.IntegerField(choices=((0,'文学类'),(1,'情感类')),default=1,null=True)
publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE,null=True)
authors = models.ManyToManyField(to='Author') def __str__(self):
return self.name def test(self):
return '方法'
在视图中使用序列化的类
实例化序列化的类产生对象,在产生对象的时候,传入需要序列化的对象
对象.data
return Response(对象.data) 返回值用Response返回
如果序列化多条 many=True(也就是queryset对象,就需要写many=True) 如果序列化一条(可以不用写many=False默认就是False)instance是要序列化的对象
from app01.app01serializer import BookSerializer #自定义的py文件下的序列化组件
from rest_framework.response import Response #返回用的 class Books(APIView):
def get(self,request):
response = {'code':100,'msg':'查询成功'}
books = models.Book.objects.all() bookser = BookSerializer(instance=books,many=True)
# 如果序列化多条,many=True(也就是queryset对象,就需要写)
print(bookser.data,type(bookser.data))
response['data'] = bookser.data
return Response(response)
SerializerMethodField 对应着一个方法:get_字段名 方法返回值是什么该字段就是什么 write_only 反序列化的时候该字段前端不显示 read_only 反序列化的时候前端可以不传这个字段
自定义py文件下的序列化组件 类下 from rest_framework import serializers # 序列化组件
from app01 import models class BookSerializer(serializers.Serializer):
#序列化出版社的详情,指定SerializerMethodField之后,可以对应一个方法,返回什么内容,publish_detail就是什么内容
publish_detail = serializers.SerializerMethodField(read_only=True)
#对应的方法固定写法get_字段名
def get_publish_detail(self,obj): #这个obj 就是app01.models.Book
print(obj,type(obj))
return {'name':obj.publish.name,'city':obj.publish.city} # 返回所有作者信息
authors = serializers.SerializerMethodField(read_only=True)
def get_authors(self,obj):
return [{'name':author.name,'age':author.age} for author in obj.authors.all()]
序列化的两种方式 |
1 Serializers没有指定表模型
source:指定要序列化那个字段,可以是字段,可以是方法
SerializerMethodFields的用法
方式1:
authors = serializer.SerializerMethodField()
def get_authors(self,obj):
return {'name':obj.publish.name,'city':obj.publish.city}
#拓展性差 如果要查询一张表完整数据 那要写很多kv键值对 方式2:
class AuthorSerializer(serializer.Serializer):
name = serializer.CharField()
age = serializer.CharField() authors = serializer.SerializerMethodField()
def get_authors(self,obj):
ret = AuthorSerializer(instance=obj.authors.all(),man=True) #instance是默认参数可以不写
return ret.data
2 ModelSerializers:指定了表模型
class Meta: model=表模型 fields = ('__all__')显示所有的字段 fields = ('id','name')显示部分字段 exclude=['name'] 排除这个字段其他内容都显示 不能和fields同时使用 depth=1跨表深度是1,官方建议不要超过10,个人建议不要超过3 重写某个字段 在Meta外部,重写某些字段,方式同Serializers
class AuthorSerializer(serializers.Serializer):
name = serializers.CharField()
age = serializers.CharField()
# class Meta:
# fields = ('__all__') serializers木有这个meta方法 只有modelserializer有 class BookSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book #哪一张模型表
# fields = ('nid','name') #显示的字段
fields = ('__all__') #显示所有字段信息
# exclude = ['name'] #排除
# depth=1
# 深度是1,官方建议不要超过10,个人建议不要超过3
category = serializers.CharField(source='get_category_display')
authors = serializers.SerializerMethodField()
def get_authors(self,obj):
# 可以写列表生成式 如果是很多的话就要在生成式里面写很多 而且拓展性很差 可以继续写serializer
ret=AuthorSerializer(instance=obj.authors.all(),many=True)
return ret.data name5= serializers.CharField(source='name') #重写name字段 与meta同级别 方式和Serializers重写或者序列化组件一样
反序列化 |
1 使用继承了Serializers序列化类的对象,反序列化
json格式转成对象,保存到数据库
在保存之前一定要先调用 对象.is_valid()方法
在自己写的序列化类中重写create方法,反序列化
重写create放法,实现序列化(根据业务需求具体实现还是自定义create方法)
在序列化类中: 序列化类中写create方法表里面需要什么字段还是要传什么字段
from rest_framework import serializers # 序列化组件
class BookSerializer(serializers.Serializer):
#反序列化创建
def create(self, validated_data):
ret = models.Book.objects.create(**validated_data)
return ret
在视图中:
from app01.app01serializer import BookSerializer #自定义py文件里为了和view视图函数隔离开 自定义文件就写serializer组件 class Books(APIView):
#使用Serializers序列化类的对象,反序列化
def post(self,request):
#实例化产生一个序列化类的对象,data是要反序列化的字典
bookser = BookSerializer(data=request.data)
if bookser.is_valid():
#清洗通过的数据
ret = bookser.create(bookser.validated_data)
return Response()
2 使用继承了ModelSerializers序列化类的对象,反序列化
json格式转成对象,保存到数据库
在保存之前一定要先调用 对象.is_valid()
在视图中 在视图中写save() 表里面需要什么字段还是要传什么字段
from django.shortcuts import render,HttpResponse,redirect from rest_framework.views import APIView
from app01 import models from rest_framework.response import Response #返回用的 # 把对象转成json格式字符串
from app01.app01serializer import BookSerializer #自定义py文件里为了和view视图函数隔离开 自定义文件就写serializer组件 class Books(APIView): # 使用继承了ModelSerializers序列化类的对象,反序列化
def post(self,request):
#实例化产生一个序列化类的对象,data是要反序列的字典
bookser = BookSerializer(data=request.data)
if bookser.is_valid(raise_exception=True): #抛出的异常有异常就返回了 下面代码不执行 可以不写if判断
#清洗通过的数据
bookser.save()
反序列化的校验 |
反序列化的校验局部校验 validate_字段名(self,value):
如果校验失败,抛出ValidationError(抛出的异常信息需要去视图层bookser.errors中取)
如果校验通过直接return value
from rest_framework import exceptions 序列化类下面写:
#反序列化的校验(局部校验,全局校验)
def validate_name(self,value): print(value)
raise exceptions.ValidationError('不能以sb开头')
# if value.startswith('sb'):
# raise ValidationError('不能以sb开头')
# return value
视图层 post请求内 校验错误信息
def post(self,request):
#实例化产生一个序列化类的对象,data是要反序列化的字典
bookser=BookSerializer(data=request.data)
# bookser.data
if bookser.is_valid(raise_exception=True): 有异常就直接返回了 下面代码不会被执行 如果执行说明已经通过了
#清洗通过的数据
bookser.save()
else:
print(bookser.errors['name'][0])
return Response()
反序列化的校验全局 validate(self,attrs) attrs所有校验通过的数据,是个字典 如果校验失败,抛出ValidationError 如果校验通过直接返回return attrs
序列化组件类中
#去局校验
def validate(self,attrs):
print(attrs) return attrs
读源码分析 |
全局和局部钩子源码部分
调用了bookser.is_valid方法才走校验---》Serlizer(没有is_valid)->BaseSerializer(is_valid) 走了self.run_validtaion方法(先从自身找)
(在Serializer找到)self.run_validation方法
Serializer中找to_internal_value
找所有的字段于是就执行了局部校验的函数
全局校验
走自身的这个方法(Serializer的)
run_validators方法super继承run_validators--->BaseSerializer没有找--->Field中有这个方法 run_validators
然后全局校验的第一步走完了
在序列化的时候,传many=True和many=False,生成的对象并不是一个对象 Serializer中的基类BaseSerializer中的__new__
序列化对象.data 的时候做了什么事?
执行了Serializer内的data方法
又执行了父类(BaserSerializer)的data方法
其实执行的是Serializer内的to_representation方法
最终执行的是每个字段对象的get_attribute方法
Serializer---》BaseSerializer ---》Field --》
self.source_attrs Field类自己的方法
每个字段source后面指定的根据 点 切分 切分后的列表(publish.name:就会被分成[publish,name])
如果是方法会执行方法,如果是字段,通过反射取出值
Field类里面的方法
instance 当前序列化的对象(从data方法中看到self.instance就是当前序列化)
从BaseSerializer data中
而BaseSerializer初始化的时候
DRF 序列化组件 序列化的两种方式 反序列化 反序列化的校验的更多相关文章
- React组件导入的两种方式(动态导入组件的实现)
一. react组件两种导入方式 React组件可以通过两种方式导入另一个组件 import(常用) import component from './component' require const ...
- vue实现组件切换的两种方式
<!DOCTYPE html> <html> <head> <title>组件的切换</title> <meta charset=&q ...
- vue之provide和inject跨组件传递属性值失败(父组件向子组件传值的两种方式)
简单介绍:当一个子组件需要用到父组件的父组件的某些参数.那么这个时候为了避免组件重复传参,使用vue的依赖注入是个不错的方法,直接在最外层组件设置一个provide,内部不管多少嵌套都可以直接取到最外 ...
- Django学习——ajax发送其他请求、上传文件(ajax和form两种方式)、ajax上传json格式、 Django内置序列化(了解)、分页器的使用
1 ajax发送其他请求 1 写在form表单 submit和button会触发提交 <form action=""> </form> 注释 2 使用inp ...
- java 的对象拷贝(有深浅拷贝两种方式,深拷贝实现的两种方式(逐层实现cloneable接口,序列化的方式来实现))
Java提高篇--对象克隆(复制)(转自:http://www.cnblogs.com/Qian123/p/5710533.html#_label0) 阅读目录 为什么要克隆? 如何实现克隆 浅克 ...
- K:java中序列化的两种方式—Serializable或Externalizable
在java中,对一个对象进行序列化操作,其有如下两种方式: 第一种: 通过实现java.io.Serializable接口,该接口是一个标志接口,其没有任何抽象方法需要进行重写,实现了Serializ ...
- 一步步分析Java深拷贝的两种方式-clone和序列化
今天遇到一道面试题,询问深拷贝的两种方法.主要就是clone方法和序列化方法.今天就来分析一下这两种方式如何实现深拷贝.如果想跳过解析的朋友,直奔"重点来了!"寻找答案. clon ...
- react学习笔记1之声明组件的两种方式
//定义组件有两种方式,函数和类 function Welcome(props) { return <h1>Hello, {props.name}</h1>; } class ...
- 使用react定义组件的两种方式
react组件的两种方式:函数定义,类定义 在定义一个组件之前,首先要明白一点:react元素(jsx)是react组件的最基本的组成单位 组件要求: 1,为了和react元素进行区分,组件名字首必须 ...
随机推荐
- 泛目录程序(莲花泛目录程序/黑帽SEO/寄生虫/莲花泛目录解析/泛目录软件)
莲花泛目录程序强大之处: 1.内容分类详细2.自动推送URL链接3.内置超强原创内容功能系统,页面深受百度搜索引擎喜爱.4.蜘蛛触发繁殖:蜘蛛触发程序任何页面,程序自动生成独立页面并引导繁殖.5.操作 ...
- codeforces#1150D. Three Religions(dp+序列自动机)
题目链接: https://codeforces.com/contest/1150/problem/D 题意: 给出长度为$n$的字符串,和$q$次询问 每次询问是,给$x$宗教增加一个字符$key$ ...
- ZR#710
雷劈数 题意: 现在给出两个整数,求出位于两个整数之间的所有的"雷劈数. 解法: 因为雷劈数特殊的性质,所以在数据范围中的雷劈数实际很少,直接暴力打表就行. CODE: #include&l ...
- 【洛谷4001】 [ICPC-Beijing 2006]狼抓兔子(最小割)
传送门 洛谷 Solution 直接跑最小割板子就好了. 代码实现 #include<stdio.h> #include<stdlib.h> #include<strin ...
- 机器学习 - 算法 - 集成算法 - 分类 ( Bagging , Boosting , Stacking) 原理概述
Ensemble learning - 集成算法 ▒ 目的 让机器学习的效果更好, 量变引起质变 继承算法是竞赛与论文的神器, 注重结果的时候较为适用 集成算法 - 分类 ▒ Bagging - bo ...
- python之scrapy模块下载中间件
知识点 使用方法: 编写一个Downloader Middlewares和我们编写一个pipeline一样,定义一个类,然后在setting中开启 Downloader Middlewares默认的方 ...
- 小D课堂 - 新版本微服务springcloud+Docker教程_4-02 微服务调用方式之ribbon实战 订单调用商品服务
笔记 2.微服务调用方式之ribbon实战 订单调用商品服务 简介:实战电商项目 订单服务 调用商品服务获取商品信息 1.创建order_service项目 2 ...
- React Native初始化项目后执行react-native run-ios,构建失败
今天是肿么了......一上班创建React Native项目,react-native run-ios运行就报错,运行不了...呜呜...... 一开始以为自己react-native run-io ...
- 资深技术Leader曹乐:如何成为技术大牛
From: https://mp.weixin.qq.com/s/QaBTm_9AJC01Isr3LLR3aw 原创: 曹乐 公众号: 再成长一次 看了下面这篇文章的话,应该会有收获. 虽然排版不好, ...
- docker search 报错
docker 出现 Error response from daemon vim /etc/containers/registries.conf [registries.search]registri ...