• drf 之 serializer序列化器


    1. 简单了解

    - 序列化字段处理原始值和内部数据类型之间的转换。它们还处理验证输入值,
    以及从其母对象检索和设置值。
    
    导入:from rest_framework import seriaalizers
    
    使用:serializers.<FieldName>
    有 serializers.Serializer 和 serializers.ModelSerializer,和 django 的 form 差不多
    
    
    - 序列化
    把Python中对象转换为json格式字符串
    
    - 反序列化
    把json格式转为为Python对象。
    
    - 序列化两大功能:
    对请求数据进行验证
    对Queryset对象进行序列化
    

    形象过程

    '''
    序列化器:
    实质: 定义了一个叫做 xx序列化器 的 <类>,  
    作用: 
    	 1. 实现 <json> 和 <对象> 的相互转化
    	 2. 实现对 前端数据 的校验功能 
    序列化       读取(read_only)obj(数据库)   -> json -> 前端
    反序列化	 前端数据校验(json)  ->  obj  -> (write_only)(数据库)
    '''
    

    2. 核心参数

    - read_only
    只读字段被包含在API输出中,但是在创建或更新操作期间不应该包含在输入中。在序列化器输入中不正确包含的任何“只读”字段将被忽略。
    只是接受,不会提交字段 例如 时间 字段
    
    - write_only
    将其设置为 True,以确保在更新或创建实例时可用该字段,但在序列化时不会序列化此字段
    
    required
    必填字段
    
    - validators
    验证字段的存在,简短的验证,例如唯一性验证,配合 UniqueValidator 等。
    
    - error_messages
    错误信息
    
    - label label
    一个短的文本字符串,可以用作HTML表单字段或其他描述元素的字段名。可用于 drf 的文档接口中友好描述
    
    - initial	一个值,应该用于预填充HTML表单字段的值。你可以通过一个可调用的方法,就像你可以使用任何常规的Django字段一样
    
    	'''
    	import datetime
    	from rest_framework import serializers
    	class ExampleSerializer(serializers.Serializer):
    		day = serializers.DateField(initial=datetime.date.today)
    	'''
    	
    - style
    控制浏览器如何渲染此字段,例如 'input_type' 和 'base_template'
    

    3. 核心字段

    ....
    

    4. 序列化

    serializer = SnippetSerializer(snippet)其中snippet是一个model类的实例
    
    serializer.data调用序列化类的 data静态方法就可以得到序列化后的对应数据。
    序列化类也可以传入Model类的querysets类型来序列化多组数据,只需要将其中的一个many参数改为True,即many=True,
    
    serializer = SnippetSerializer(querysets)
    
    serializer.data
    通过以上的操作得到的数据类型为python的基本数据类型,可以通过一下方式将数据转化成json数据
    from rest_framework.renderers import JSONRenderer
    content = JSONRenderer().render(serializer.data)
    

    5. 反序列化

    首先我们需要将json数据转化成流,然后在转化成python基本的数据结构
    import io
    stream = io.BytesIO(content)通过io模块将json数据类型转化成流
    
    data = JSONParser().parse(stream)将流转化成python基本的数据结构
    
    serializer = SnippetSerializer(data=data)反序列化数据
    
    serializer.is_valid()校验数据
    
    serializer.validated_data查看校验通过的数据
    
    serializer.save()保存数据(调用序列化类的creat方法)
    ModelSerializer同Serializer很相似,只不过建立了序列化类和Model类的强联系,简化了代码,提高了代码的可重用性。
    

    6. serializer.Serializer示例(手机号登录验证)

    import re
    from rest_framework import serializers
    from rest_framework.exceptions import ValidationError
    from django_redis import get_redis_connection
    
    
    
    # 手机号验证
    def phone_validator(value):
    	if not re.match(r"^(1[3|4|5|6|7|8|9])d{9}$", value):
    		raise ValidationError('手机格式错误')
    		
    class MessageSerializer(serializers.Serializer):
    	phone = serializers.CharField(label="手机号", validators=[phone_validator])
    
    		
    # 短信验证码验证
    class LoginSerializer(serializers.Serializer):
    	"""
    	1. 校验手机号是否合法
    	2. 校验验证码,redis
    		- 无验证码
    		- 有验证码,输入错误
    		- 有验证码,成功
    	"""
    	phone = serializers.CharField(label="手机号", validators=[phone_validator])
    	code = serializers.CharField(label="验证码", )
    	nickName = serializers.CharField(label="用户昵称")
    	avatarUrl = serializers.CharField(label="用户昵称")
    
    	def validate_code(self, value):
    		if len(value) != 4:
    			raise ValidationError('验证码格式错误')
    		if not value.isdecimal():
    			raise ValidationError('验证码格式错误')
    
    		phone = self.initial_data.get('phone')
    		conn = get_redis_connection()
    		code = conn.get(phone)
    		if not code:
    			raise ValidationError('验证码过期')
    		if value != code.decode('utf-8'):
    			raise ValidationError('验证码错误')
    		return value
    

    7. 自定义钩子函数:

    # 单一校验,value为校验数据,注意一定要以 validate_<Filed name> 为名称
    def validate_code(self, value):
    	if len(value) != 4:
    		raise ValidationError('验证码格式错误')
    	if not value.isdecimal():
    		raise ValidationError('验证码格式错误')
    
    	phone = self.initial_data.get('phone')
    	conn = get_redis_connection()
    	code = conn.get(phone)
    	if not code:
    		raise ValidationError('验证码过期')
    	if value != code.decode('utf-8'):
    		raise ValidationError('验证码错误')
    	return value
    

    8. serializer.Serializer 嵌套使用

    """
    # 需要校验的前端数据
    data: {
    		cover_url:that.data.imagelist[0].cos_path,
    		token:{"token":that.data.userinfo.token},
    		imagelist: that.data.imageInfo,
    		content:that.data.content,
    		location: that.data.localPath,
    		topic: that.data.topicId,
    	  },
    # 实际数据
    {
    	'imagelist': [OrderedDict([('cos_path',
    		'http://images-1301082770.cos.ap-beijing.myqcloud.com/publish/x8g2y1fl1579067901828.jpg'), (
    		'key', 'x8g2y1fl1579067901828.jpg')]), OrderedDict([('cos_path',
    		'http://images-1301082770.cos.ap-beijing.myqcloud.com/publish/gljj9lnc1579067901834.jpg'), (
    		'key', 'gljj9lnc1579067901834.jpg')])],
    	'token': OrderedDict([('token', '738089ad-e070-4991-bddc-bba45a262780')]),
    	'cover_url': 'http://images-1301082770.cos.ap-beijing.myqcloud.com/publish/x8g2y1fl1579067901828.jpg'
    	'content': '今天天气有雾霾。。。。。',
    	'location': '北京市昌平区政府街19号',
    	'topic': < Topic: 大雪之日 >
    }
    """
    
    # 嵌套使用,many=True,前提条件:imagelist有至少两条校验数据
    class UserinfoSerializer(serializers.Serializer):
    	token = serializers.CharField()
    
    
    class ImageSerializer(serializers.Serializer):
    	cos_path = serializers.CharField()
    	key = serializers.CharField()
    
    
    class ArticleDetailSerializer(serializers.ModelSerializer):
    	imagelist = ImageSerializer(many=True)
    	token = UserinfoSerializer()
    	cover_url = serializers.CharField()
    
    	class Meta:
    		model = models.ArticleDetail
    		exclude = ['article', 'mention_user', 'browse_user',
    				   'browse_count', 'share_count', 'enshrine_count', 'comment_count']
    

    9. 对所有字段进行扩展验证

    我们需要在序列化器中定义一个名字为(validate())的方法,来补充对所有字段进行扩展验证的逻辑。
    
    def validate(self, attrs):
    
    	'''
    	对多个字段进行验证
    	:param attrs: 前段传递的字典数据
    	:return: 验证成功:返回attrs;验证失败:返回错误信息
    	'''
    	# 验证逻辑:这里需要验证的是bread大于bcomment
        read = attrs.get('read')
        comment = attrs.get('comment')
    
        if bread < bcomment:
            # 失败
            raise serializers.ValidationError('read需要大于comment')
    
        # 成功
        return attrs
    

    10. 验证后的字典数据 ---> 模型数据(添加或者修改)

    这里,我们已将到了数据反序列化的最后一步操作了。
    
    同样,我们也应该知道,将验证后的字典数据转模型数据的实质,其实就是将验证过的字典数据添加到数据库中。
    
    那么,对于将数据保存到数据库中的操作一共就两种:一种是添加数据的操作,一种是修改数据的操作。
    

    11. 添加数据(create)

    - 我们,想要添加数据,就需要在序列化器类中定义一个create()方法。
    在这里,我们需要返回添加的数据给前端,因为我们定义的API是遵守RESTful设计风格的。
    
    
    - 当我们创建序列化对象时,只传递data数据,就表示我们需要向数据库里添加数据。
    所以,当序列化器对象调用save()方法时,会自动调用序列化器类中的create()方法。
    
    
    
    def create(self, validated_data):
    	'''
    	序列化器进行新增数据的方法
    	:param validated_data: 通过验证的字典数据
    	:return:根据RESTful设计方式,需要将添加的数据返回
    	'''
    	return ORM添加数据的语句(模型类.objects.create(**validated_data))
    	
    	
    例如:
    
    def create(self, validated_data):
    	'''
    	序列化器进行新增数据的方法
    	:param validated_data: 通过验证的字典数据
    	:return:根据RESTful设计方式,需要将添加的数据返回
    	'''
    
    	return BookInfo.objects.create(**validated_data)
    

    12. 修改数据

    我们,想要修改数据时,需要在序列化器类中定义一个update()方法。
    
    def update(self, instance, validated_data):
        '''
        序列化器进行修改数据的方法
        :param instance: 需要修改的模型对象
        :param validated_data: 前端传递的字典数据
        :return: 根据RESTful设计方式,需要将修改的数据返回
        '''
        
        # 新值覆盖旧值
        instance.字段名 = validated_data.get(字段名)
        instance.save()
        return instance
    	
    	
    例如:
    
    def update(self, instance, validated_data):
    	'''
    	序列化器进行修改数据的方法
    	:param instance: 需要修改的模型对象
    	:param validated_data: 前端传递的字典数据
    	:return: 根据RESTful设计方式,需要将修改的数据返回
    	'''
    
    	# 新值覆盖旧值
    	instance.title = validated_data.get('title')
    	instance.pub_date = validated_data.get('pub_date')
    	instance.read = validated_data.get('read')
    	instance.comment = validated_data.get('comment')
    	instance.save()
    
    	return instance
    	
    我们同样也需要将修改的数据返回给前端。
    
    
    -注意:
    
    '''
    当我们创建序列化器对象时,传递了instance和data数据,就表示我们需要进行数据的修改操作。
    
    所以,当我们使用序列化器对象调用save()方法时,会自动调用序列化器类中的update()方法。
    '''
    希望你眼眸有星辰,心中有山海,从此以梦为马,不负韶华
  • 相关阅读:
    UIAutomation学习入门
    Global.asax详解
    iOS开发之UINavigationController
    iOS开发之控制器创建与加载(生命周期)
    iOS开发之自定义弹出的键盘
    iOS开发之UIWindow
    iOS开发之UIPickerView
    iOS开发之iOS程序的启动过程
    iOS开发之UIApplication和delegate
    iOS开发之UIApplication
  • 原文地址:https://www.cnblogs.com/daviddd/p/12275231.html
Copyright © 2020-2023  润新知