序列化器-Serializer

目录

序列化器-Serializer

零 序列化介绍

api接口开发,最核心最常见的一个过程就是序列化,所谓序列化就是把数据转换格式,序列化可以分两个阶段:

  • 序列化: 把我们识别的数据转换成指定的格式提供给别人。

    例如:我们在django中获取到的数据默认是模型对象,但是模型对象数据无法直接提供给前端或别的平台使用,所以我们需要把数据进行序列化,变成字符串或者json数据,提供给别人。

  • 反序列化:把别人提供的数据转换/还原成我们需要的格式。

    例如:前端js提供过来的json数据,对于python而言就是字符串,我们需要进行反序列化换成模型类对象,这样我们才能把数据保存到数据库中。

一 序列化组件介绍

#1  作用:
    1). 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
    	-Book--序列化器--->字典--通过drf:Response--》json格式字符串--->传给前端
    2). 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
    	json格式数据---drf:Request-->字典---序列化器---》Book

    3). 反序列化,完成数据校验功能  

二 序列化组件简单使用

1 基本使用

1.1 序列化的使用

-写一个序列化类继承serializers.Serializer
-在类中写要序列化的字段
-在视图类中,实例化得到一个序列化类的对象instance,把要序列化的数据传入
	ser=BookSerializer(instance=res, many=True)
-得到字典
	ser.data就是序列化后的字典 

1.2 serializer 与 ModelSerializer

# serializer
	-serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。serializer是独立于数据库之外的存在。

# ModelSerializer
	-如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

2 序列化类字段类型和字段参数

# 字段类型(记列的这几个)
	-IntegerField
    -CharField
    -DecimalField
    -DateTimeField
    -。。。跟models中大差不差
    
# 常用字段参数
	-选项参数
        max_length	    最大长度
        min_lenght	    最小长度
        allow_blank	    是否允许为空
        trim_whitespace	是否截断空白字符
        max_value	    最小值
        min_value	    最大值
    
    -通用参数
    	#重点
        read_only	表明该字段仅用于序列化输出,默认False
        write_only	表明该字段仅用于反序列化输入,默认False
        
        # 掌握
        required	表明该字段在反序列化时必须输入,默认True
        default	    反序列化时使用的默认值
        allow_null	表明该字段是否允许传入None,默认False
        
        # 了解
        validators	    该字段使用的验证器
        error_messages	包含错误编号与错误信息的字典

3 read_only和write_only

    read_only	# 表明该字段仅用于序列化输出,默认False
    write_only	# 表明该字段仅用于反序列化输入,默认False    

# 代码示例
    class BookSerializer(serializers.Serializer):
        # 要序列化哪个字段
        id = serializers.IntegerField(required=False)
        # id = serializers.CharField()
        title = serializers.CharField(max_length=32,min_length=2,read_only=True)
        price = serializers.DecimalField(max_digits=5, decimal_places=2)

        # 序列化的时候看不到
        publish = serializers.CharField(max_length=32,validators=[check,],write_only=True)

4 代码实现

serializer.py

from rest_framework import serializers
class BookSerializer(serializers.Serializer):
    # 要序列化哪个字段
    id=serializers.IntegerField()
    # id=serializers.CharField()
    title=serializers.CharField(max_length=32)
    price=serializers.DecimalField(max_digits=5, decimal_places=2)
    # publish=serializers.CharField(max_length=32)

models.py

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.CharField(max_length=32)

views.py

from app01 import models
from app01.serializer import BookSerializer
class Book(APIView):
    def get(self, request, *args, **kwargs):

        res=models.Book.objects.all()
        # 借助序列化器
        # 如果是多条,就是many=True
        # 如果是单个对象,就不写
        ser=BookSerializer(instance=res, many=True)
        # 通过序列化器得到的字典
        # ser.data
        print(ser.data)
        return Response(ser.data)

urls.py

path('books/', views.Book.as_view()),

三 序列化

1 修改,删除接口代码

views.py

#1) 修改接口	def put(self, request, id):        # 通过id取到对象        res = {'code': 100, 'msg': ''}        try:            book = models.Book.objects.get(id=id)            ser = BookSerializer(instance=book, data=request.data)            ser.is_valid(raise_exception=True)            ser.save()            res['msg'] = '修改成功'            res['result'] = ser.data        except Exception as e:            res['code'] = 101            res['msg'] = str(e)        return Response(res)#2) 删除接口    def delete(self,request,id):        response = {'code': 100, 'msg': '删除成功'}        models.Book.objects.filter(id=id).delete()        return Response(response)

serializer.py

class BookSerializer(serializers.Serializer):    id = serializers.IntegerField(required=False)    title = serializers.CharField(max_length=32,min_length=2)    price = serializers.DecimalField(max_digits=5, decimal_places=2)    publish = serializers.CharField(max_length=32)#1) 重写新增接口    def create(self, validated_data):        res=models.Book.objects.create(**validated_data)        print(res)        return res#2) 重写更新接口    def update(self, instance=book, validated_data):        book.title=validated_data.get('title')        book.price=validated_data.get('price')        book.publish=validated_data.get('publish')        book.save()        return book

四 序列化高级用法

1 高级用法之source

1) 修改返回到前端的字段名	# source=title    字段名就不能再叫title	name = serializers.CharField(max_length=32, min_length=2, source='title')    2) 如果表模型中有方法	# 执行表模型models中的test方法,并且把返回值赋值给xxx	xxx = serializers.CharField(source='test')    3) source支持跨表操作	# 表模型models中有外键关联,可以查询的时候使用 【对象.】 操作进行跨表取值	addr = serializers.CharField(source='publish.addr')4) 外键关联字段,如果查询该字段名字,结果是一个对象,需要重写__str__方法,控制打印的内容。    # 希望你们去看一下源码,内部如何实现的

2 高级用法之SerializerMethodField

### 取出图书的出版社详细信息(id,name,addr)## 【注意】:在get请求下使用,如果是post请求,需要使用另外的序列化类

2.1 方案一: 使用Serialize序列化类

## 第一种方案,使用Serialize序列化类class BookSerializer(serializers.Serializer):    id = serializers.IntegerField(required=False)    name = serializers.CharField(max_length=32,min_length=2,source='title')    price = serializers.DecimalField(max_digits=5, decimal_places=2)    publish = serializers.SerializerMethodField()    def get_publish(self,obj):        dic={'name':obj.publish.name,'addr':obj.publish.addr}        return dic

2.2 方案二: 使用ModelSerializer序列化类

## 第二种方案,使用ModelSerializer序列化类class BookModelSerializer(serializers.ModelSerializer):    class Meta:        model = models.Book        fields = '__all__'    publish = serializers.SerializerMethodField()    def get_publish(self,obj):        dic={'name':obj.publish.name,'addr':obj.publish.addr}        return dic 

2.3 方案三: 使用【序列化类的嵌套/子序列化】

## 第三种方案,使用【序列化类的嵌套】class PublishSerializer(serializers.ModelSerializer):    class Meta:        model = models.Publish        fields = ['name', 'addr']        # fields = '__all__'        extra_kwargs = {            'publish': {'read_only': True}        }class BookModelSerializer(serializers.ModelSerializer):    publish_name = PublishSerializer(source='publish')  # 配合extra_kwargs就可以既显示publish信息,又可以存储publish_id    class Meta:        model = models.Book        fields = '__all__'

五 反序列化

1 序列化器的字段校验功能

-使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。-在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。-验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。-验证成功,可以通过序列化器对象的validated_data属性获取数据。-在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
# 三种方式-字段自己的校验规则(max_length...)-validators的校验    publish = serializers.CharField(max_length=32,validators=[check,])    def check(data):        if len(data)>10:            raise ValidationError('最长不能超过10')        else:            return data-局部和全局钩子    # 局部钩子,validate_字段名,需要带一个data,data就是该字段的数据    def validate_title(self, data):        if data.startswith('sb'):            raise ValidationError('不能以sb开头')        else:            return data    # 全局钩子    def validate(self, attrs):        title=attrs.get('title')        publish=attrs.get('publish')        if title==publish:            raise ValidationError('书名不能跟出版社同名')        else:            return attrs

2 序列化器的保存功能

# 如果序列化类继承的是Serializer,必须重写create方法!!!# 使用方式	-视图类     def post(self, request):        print(request.data)  		# request.data是我们要反序列化保存的数据,把他传值给序列化器的 data 参数, 进行校验。        ser = BookSerializer(data=request.data)        # 对序列化的对象ser 使用is_valid() 方法进行校验。        if ser.is_valid():            ser.save()  # 校验成功,保存到数据库中            return Response(ser.data)        else:            # 没有校验通过,返回的错误信息            return Response(ser.errors)    -序列化类      class BookSerializer(serializers.Serializer):		···        def create(self, validated_data):            # 为什么要重写create?            res=models.Book.objects.create(**validated_data)            print(res)            return res		def update(self, instance, validated_data):            """更新,instance为要更新的对象实例"""                        return instance

六 模型类序列化器ModelSerilizer

1) 原来用的Serilizer跟表模型没有直接联系, 模型类序列化器ModelSerilizer,跟表模型有对应关系2) 使用	class BookModelSerializer(serializers.ModelSerializer):        class Meta:            model=表模型                   		  # 跟哪个表模型建立关系            fields=[字段,字段]             			# 序列化的字段,反序列化的字段            fields='__all__'              			# 所有字段都序列化,反序列化【使用较多】            exclude=[字段,字段]            			# 排除哪些字段(不能跟fields同时使用)            read_only_fields=['price','publish']  	# 序列化显示的字段            write_only_fields=['title']           	# 反序列化需要传入的字段            extra_kwargs ={'title':{'max_length':32,'write_only':True}} 	# 【字典的key就是写的字段,自带__all__,可以写read_only, write_only, 控制我们序列化、反序列化的字段】            depth=1  							# 了解,跨表1查询,最多建议写3                # 重写某些字段, 重写或者新增的字段,必须在fields中添加,否则会报错。          publish = serializers.CharField(max_length=32,source='publish.name')        # 局部钩子,全局钩子,跟原来完全一样3) 新增,修改	-统统不用重写create和update方法了,在ModelSerializer中重写了create和update   

七 many=True源码分析,局部全局钩子源码解析

1 many=True源码分析

# many=True源码分析1) many=True-__init__----->一路找到了BaseSerializer---》__new__决定了生成的对象是谁"""    -序列化组件,先调用__new__方法,如果many=True,生成ListSerializer对象,如果为False,生成Serializer对象	-序列化对象.data方法--调用父类data方法---调用对象自己的to_representation(自定义的序列化类无此方法,去父类找)	-Serializer类里有to_representation方法,for循环执行attribute = field.get_attribute(instance)	-再去Field类里去找get_attribute方法,self.source_attrs就是被切分的source,然后执行get_attribute方法,source_attrs	-当参数传过去,判断是方法就加括号执行,是属性就把值取出来"""

2 局部全局钩子源码解析

# 局部全局钩子源码解析2) 入口是is_valid()---》BaseSerializer--》is_valid---》self._validated_data = self.run_validation(self.initial_data)	-Serializer这个类的:self.run_validationdef run_validation(self, data=empty):        value = self.to_internal_value(data)  # 局部字段自己的校验和局部钩子校验        try:            self.run_validators(value)            value = self.validate(value)  # 全局钩子的校验        except (ValidationError, DjangoValidationError) as exc:            raise ValidationError(detail=as_serializer_error(exc))        return value
上一篇:npm publish 400 maintainers


下一篇:Windows中正在使用的端口如何关闭