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

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']

猜你喜欢

转载自www.cnblogs.com/daviddd/p/12275231.html