zoukankan      html  css  js  c++  java
  • drf 序列化

    drf 序列化

    什么是序列化与反序列化

    • 序列化:就是把对象转化为可以进行网络传输的数据(程序语言转换为JSON/XML)
    • 反序列化:就是把网络传输的数据转化为对象进行使用(JSON/XML转换为程序语言)

    序列化的作用

    1. 进行数据的校验
    2. 对数据对象进行转换

    简单认识序列化

    首先来进行准备工作:

    from django.db import models
    
    class User(models.Model):
        # choices的字段,直接获取只能获取 0 | 1 | 2
        # 想获取 值后 的映射关系 男 | 女 | 哇塞 用  get_字段名_display()
        # eg:user_obj.get_sex_diaplay()
        SEX_CHOICES = [
            (0, '男'),
            (1, '女'),
            (2, '哇塞')
        ]
        username = models.CharField(max_length=64, unique=True)
        password = models.CharField(max_length=64)
        sex = models.IntegerField(choices=SEX_CHOICES, default=0)
        icon = models.ImageField(upload_to='icon', default='icon/default.png')
        create_time = models.DateTimeField(auto_now_add=True, null=True)
        is_delete = models.BooleanField(default=False)
    
        class Meta:
            db_table = 'old_boy_user'
            verbose_name = '用户'
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.username
    

    自定义序列化类

    定义

    通过继承rest_framework.serializers中的Serializer类进行定义,但需要有如下几个注意点:

    1. 参与序列化的属性名必须与model类的属性字段名相同
    2. 不需要序列化的属性字段在序列化类中不需要声明
    3. 方法序列化字段,不需要在model类中有字段属性对应,值来源于get_字段方法,序列化字段可以完全自定义,也可以与model类中有字段属性相同

    如:

    from rest_framework import serializers
    from django.conf import settings
    from . import models
    # 序列化
    class UserSerializer(serializers.Serializer):
        username = serializers.CharField()
        
        # 不需要序列化的不需要声明
        # password = serializers.CharField()
        
        sex = serializers.IntegerField()   # 只能返回数字
    	# 自定义序列化字段
        gender = serializers.SerializerMethodField()
        def get_gender(self, user_obj):
            return user_obj.get_sex_display()    # 返回性别
        
        # icon = serializers.ImageField()
        # 二次资源需要返回完整的url链接
        icon = serializers.SerializerMethodField()
        def get_icon(self, user_obj):
            icon_url = 'http://127.0.0.1:8000{}{}'.format(settings.MEDIA_URL, user_obj.icon)
            return icon_url
    

    常用字段类型

    字段 字段构造方式
    BooleanField BooleanField()
    NullBooleanField NullBooleanField()
    CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
    EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
    RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
    SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
    URLField URLField(max_length=200, min_length=None, allow_blank=False)
    UUIDField UUIDField(format='hex_verbose') format: 1) 'hex_verbose'"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex'"5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
    IPAddressField IPAddressField(protocol='both', unpack_ipv4=False, **options)
    IntegerField IntegerField(max_value=None, min_value=None)
    FloatField FloatField(max_value=None, min_value=None)
    DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
    DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
    DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
    TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
    DurationField DurationField()
    ChoiceField ChoiceField(choices) choices与Django的用法相同
    MultipleChoiceField MultipleChoiceField(choices)
    FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
    ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
    ListField ListField(child=<a_field_instance>, min_length=None, max_length=None)
    DictField DictField(child=<a_field_instance>)

    选项参数

    参数名称 作用
    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 包含错误编号与错误信息的字典
    label 用于HTML展示API页面时,显示的字段名称
    help_text 用于HTML展示API页面时,显示的字段帮助提示信息

    使用自定义序列化对象

    定义好Serializer类后,就可以创建Serializer对象了。

    Serializer的构造方法为:

    Serializer(instance=None, data=empty, **kwargs)
    

    说明:

    1. 用于序列化时,将模型类对象传入instance参数,当序列化数据为单列集合时,此时many=True必须明确

      补充:单列集合就是具有索引的集合,例如列表,元组,集合,django中的 QuerySet

    2. 除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如

      serializer = UserSerializer(account, context={'request': request})
      

      通过context参数附加的数据,可以通过Serializer对象的context属性获取。

    案例

    from rest_framework.views import APIView
    from utils_home.response import APIResponse
    from . import models, serializers
    class UserAPIView(APIView):
        # 序列化对象:
        # UserSerializer(序列化数据, many)
        # 1)序列化数据可以为User类的单个对象,many=False(默认,可以省略不写)
        # 2)序列化数据可以为状态User类的多个对象的单列集合
        #       [] () {} QuerySet,此时many=True必须明确
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if pk:  # 获取单个资源
                user_obj = models.User.objects.filter(pk=pk).first()
                if not user_obj:
                    return APIResponse(1, 'pk error')
                user_obj_data = serializers.UserSerializer(user_obj).data
                return APIResponse(0, 'ok', results=user_obj_data)
    
            # 获取多个资源
            user_query = models.User.objects.all()
            user_ser = serializers.UserSerializer(user_query, many=True)
            user_list_data = user_ser.data
            return APIResponse(0, 'get ok', results=user_list_data)
    

    简单认识反序列化

    自定义反序列化类

    同样通过继承rest_framework.serializers中的Serializer类进行定义,但需要有如下几个注意点:

    1. 在字段类型后定义基础校验规则
    2. 基础校验完毕,可以在局部钩子方法中进行单个字段校验规则的扩展
    3. 在局部钩子校验完毕,在全局钩子中完成多个字段协同校验
    4. 如果需要提供数据的增加或修改功能,需要重写create或update方法,完成数据的入库

    如:

    from rest_framework import serializers
    from django.conf import settings
    from . import models
    # 反序列化
    class UserDeserializer(serializers.Serializer):
        # 1)默认校验
        username = serializers.CharField(
            min_length=3,
            error_messages={
                'min_length': '用户名太短'
            }
        )
        password = serializers.CharField(
            min_length=3,
            error_messages={
                'min_length': '密码太短'
            }
        )
        re_password = serializers.CharField(
            min_length=3,
            required=True,
            error_messages={
                'min_length': '确认密码太短',
                'required': '确认密码不能为空'
            }
        )
    
        # 有默认值的字段,前台可能提供,可能提供,这样的字段用required=False处理
        sex = serializers.IntegerField(required=False)
    
        # 2)局部钩子: validate_字段名(self, 字段值)
        def validate_username(self, value):
            if 'sb' in value:
                raise serializers.ValidationError('用户名包含敏感词汇')
            return value
    
        # 3)全局钩子:validate(self, 所有字段值)
        def validate(self, attrs):
            print(attrs)
            password = attrs.get('password')
            # 校验通过后,要完成数据的增加,该增加不参与,要从数据们中剔除
            re_password = attrs.pop('re_password')
            if password != re_password:
                raise serializers.ValidationError({'re_password': '两次密码不一致'})
            return attrs
    
        # 4)完成model类对象的增加,必须重写create方法
        def create(self, validated_data):
            try:
                return models.User.objects.create(**validated_data)
            except:
                raise IOError('数据库入库失败')  # 数据库异常在异常模块中完善
    
    

    使用自定义反序列化对象

    说明:

    1. 反序列化数据可以为单个数据字典,many=False或者不写

    2. 用于反序列化时,将要被反序列化的数据传入data参数,当序列化数据为单列集合时,此时many=True必须明确

    3. 反序列化数据必须赋值给data关键字参数,才能进行数据校验

    4. 序列化对象.is_valid(raise_exception=True)校验失败会自动返回错误信息给前台

    5. if 序列化对象.is_valid(): 可以自定义校验成功与失败分支的返回结果

      成功可以完成新增或修改,失败错误信息在 序列化对象.errors 中

    from rest_framework.views import APIView
    from utils_home.response import APIResponse
    from . import models, serializers
    class UserAPIView(APIView):
        # 反序列化请求数据
        def post(self, request, *args, **kwargs):
            request_data = request.data
            print(request_data)
            user_ser = serializers.UserDeserializer(data=request_data)
            # 自动返回错误信息
            # user_ser.is_valid(raise_exception=True)
            if user_ser.is_valid():  # 自定义处理校验成功的逻辑
                user_obj = user_ser.save()
                return APIResponse(0, 'ok',
                    results=serializers.UserSerializer(user_obj).data
                )
            else:  # 自定义返回错误信息
                return APIResponse(1, 'failed', results=user_ser.errors)
    

    序列化器(序列化与反序列化整合)

    自定义序列化器

    说明:

    1. 参与序列化与反序列化的字段(包括自定义字段)都必须明确

    2. 通过 read_only=True 表明该字段只参与序列化

    3. 通过 write_only=True 表明该字段只参与反序列化

    4. 参与反序列化,但是是选填字段(前台可以提供或不提供),用 required=False 处理

    5. 要完成数据库增加,需要重写 create 方法

    6. 要完成数据库更新,需要重写 update 方法

      • instance参数传入的是自定义传入的要更新的原数据(pk | obj | queryset)
      • validated_data:是校验通过后的新数据
    from rest_framework import serializers
    from django.conf import settings
    from . import models
    # 序列化与反序列化整合
    class UserV2Serializer(serializers.Serializer):    
        username = serializers.CharField(min_length=3)
        # 只参与反序列化 write_only=True
        password = serializers.CharField(write_only=True, min_length=3)
        sex = serializers.IntegerField(write_only=True, required=False)
        re_password = serializers.CharField(write_only=True, min_length=3, required=True)
        # 只参与序列化 read_only=True
        gender = serializers.SerializerMethodField(read_only=True)
        def get_gender(self, user_obj):
            return user_obj.get_sex_display()
        icon = serializers.SerializerMethodField(read_only=True)
        def get_icon(self, user_obj):
            icon_url = 'http://127.0.0.1:8000{}{}'.format(settings.MEDIA_URL, user_obj.icon)
            return icon_url
    
        def validate_username(self, value):
            if 'sb' in value:
                raise serializers.ValidationError('用户名包含敏感词汇')
            return value
    
        def validate(self, attrs):
            print('序列化内:', self.context)
            password = attrs.get('password')
            re_password = attrs.get('re_password')
            if password:
                if re_password:
                    attrs.pop('re_password')
                    if password != re_password:
                        raise serializers.ValidationError({'re_password': '两次密码不一致'})
                else:
                    raise serializers.ValidationError({'re_password': '密码必须确认'})
            return attrs
    
        # 增
        def create(self, validated_data):
            try:
                return models.User.objects.create(**validated_data)
            except:
                raise IOError('数据库入库失败')
        # 改
        def update(self, instance, validated_data):
            # instance的值外部反序列化传入要更新的自定义标识决定
            instance.update(**validated_data)
            return instance.first()
    

    使用序列化器完成五大接口

    from rest_framework.views import APIView
    from utils_home.response import APIResponse
    from . import models, serializers
    class UserV2APIView(APIView):
        # 单取、群取
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            # 单取
            if pk:
                user_obj = models.User.objects.filter(pk=pk, is_delete=False).first()
                if not user_obj:
                    return APIResponse(1, 'pk error')
                user_obj_data = serializers.UserV2Serializer(user_obj).data
                return APIResponse(0, 'ok', results=user_obj_data)
            
    		# 群取
            user_query = models.User.objects.filter(is_delete=False).all()
            user_ser = serializers.UserV2Serializer(user_query, many=True)
            user_list_data = user_ser.data
            return APIResponse(0, 'ok', results=user_list_data)
    
        # 单增
        def post(self, request, *args, **kwargs):
            request_data = request.data
            print(request_data)
            user_ser = serializers.UserV2Serializer(data=request_data)
            if user_ser.is_valid():
                user_obj = user_ser.save()
                return APIResponse(0, 'ok',
                    results=serializers.UserV2Serializer(user_obj).data
                )
            else:
                return APIResponse(1, 'failed', results=user_ser.errors)
    
        # 单整体改
        def put(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if not pk:
                return APIResponse(1, 'pk error')
    
            user_query = models.User.objects.filter(pk=pk, is_delete=False)
            if not user_query:
                return APIResponse(1, 'user error')
    
            # 第一种:user_query完成数据的更新
            # user_query = models.User.objects.filter(pk=pk)
            # user_query.update(**kwargs)
    
            # 第二种:user_obj完成数据的更新
            # user_obj = models.User.objects.filter(pk=pk).first()  # type: models.User
            # user_obj.username = 'new_username'
            # ...
            # user_obj.save()
    
    
            request_data = request.data
            user_ser = serializers.UserV2Serializer(instance=user_query, data=request_data)
            if user_ser.is_valid():
                # save的返回值是由update内部自定义的返回值决定
                user_obj = user_ser.save()
                return APIResponse(0, 'ok',
                    results=serializers.UserV2Serializer(user_obj).data
                )
            else:
                return APIResponse(1, 'failed', user_ser.errors)
    
        # 单局部改
        def patch(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if not pk:
                return APIResponse(1, 'pk error')
            user_query = models.User.objects.filter(pk=pk, is_delete=False)
            if not user_query:
                return APIResponse(1, 'user error')
            request_data = request.data
            # 局部数据修改,设置 partial=True
            # 视图类给序列化类传递自定义参数 context=值 值一般用字典
            #       在序列化类的钩子函数中用self.context获取传入的值
            user_ser = serializers.UserV2Serializer(context={'arg': '我是视图的'}, partial=True, instance=user_query, data=request_data)
            if user_ser.is_valid():
                user_obj = user_ser.save()
                return APIResponse(0, 'ok',
                	results=serializers.UserV2Serializer(user_obj).data
                 )
            else:
                return APIResponse(1, 'failed', user_ser.errors)
    
        # 单删
        def delete(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if not pk:
                return APIResponse(1, 'pk error')
            user_obj = models.User.objects.filter(pk=pk, is_delete=False).first()
            if not user_obj:
                return APIResponse(1, '删除失败')
            user_obj.is_delete = True
            user_obj.save()
            return APIResponse(0, '删除成功')
    
  • 相关阅读:
    Windows XP下 Android开发环境 搭建
    Android程序的入口点
    在eclipse里 新建android项目时 提示找不到proguard.cfg
    64位WIN7系统 下 搭建Android开发环境
    在eclipse里 新建android项目时 提示找不到proguard.cfg
    This Android SDK requires Android Developer Toolkit version 20.0.0 or above
    This Android SDK requires Android Developer Toolkit version 20.0.0 or above
    Android requires compiler compliance level 5.0 or 6.0. Found '1.4' instead
    Windows XP下 Android开发环境 搭建
    Android程序的入口点
  • 原文地址:https://www.cnblogs.com/Hades123/p/11461312.html
Copyright © 2011-2022 走看看