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=‘表中字段‘ 自定义的字段不能和表中的字段名一样
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 ‘方法‘
在视图中使用序列化的类
实例化序列化的类产生对象,在产生对象的时候,传入需要序列化的对象(queryset)
对象.data
return Response(对象.data) 返回值用Response返回
如果序列化多条 many=True(也就是queryset对象,就需要写) 如果序列化一条(可以不写)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序列化类的对象,反序列化 在自己写的序列化类中重写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序列化类的对象,反序列化
在视图中 在视图中写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): #抛出的异常前端可以看到 #清洗通过的数据 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
独源码分析
全局和局部钩子源码部分
在序列化的时候,传many=True和many=False,生成的对象并不是一个对象
bookse.data 之前执行过,直接返回
get_attribute(instance,self.source_attrs)
self.source_attrs 是source指定的通过,切分后的列表
instance 当前循环到的book对象