(day72)自定义序列化推导、Serializer类序列化、ModelSerializer类、标准三流

一、自定义序列化过程(推导)

以用户get请求功能为例,

  1. orm操作数据库查询数据对象
  2. 序列化数据成可以返回给前台的数据(json模块支持的类型)
  3. 返回数据给前台
from rest_framework.views import APIView
from rest_framework.response import Response
from django.conf import settings
from . import models

# 一、自定义序列化过程
class UserV1APIView(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        # 一、单查
        if pk:
            # 1. orm操作数据库查询数据对象
            user_dic = models.User.objects.filter(is_delete=False, pk=pk).values('username', 'sex', 'img').first()
            if not user_dic:  # 判断用户是否存在
                return Response({
                    'status': 1,
                    'msg': 'pk error',
                }, status=400)
            
            # 2. 序列化数据成可以返回给前台的数据(json模块支持的类型)
            user_dic['img'] = '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, user_dic.get('img'))
            # 3. 返回数据给前台
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': user_dic
            })
        else:
            # 二、群查
            # 1. orm操作数据库查询数据对象
            user_query = models.User.objects.filter(is_delete=False).values('username', 'sex', 'img').all()
            # 2. 序列化数据成可以返回给前台的数据(json模块支持的类型)
            for user_dic in user_query:
                user_dic['img'] = '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, user_dic.get('img'))
            user_list = list(user_query)
            # 3. 返回数据给前台
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': user_list
            })

二、Serializer类:底层序列化(了解)

(一)视图类序列化过程

其实就是讲自定义序列化过程封装成了一个文件中的UserSerializer类

  1. 设置序列化字段,字段名要与处理model类的属性名对应
  2. model类中没有在UserSerializer类中声明的字段不会被序列化
  3. 自定义序列化字段:
    • 字段类型为SerializerMethodField(),对应的值由自定义get_自定义字段名(self, model_obj) 方法提供
    • 一般值都与参与序列化的mode_obj有关
# api/model.py文件
from django.db import models
class User(models.Model):
    SEX_CHOICES = (
        (0, '女'),
        (1, '男'),
    )
    username = models.CharField(max_length=64, verbose_name='用户名', blank=True, unique=True)
    password = models.CharField(max_length=64, verbose_name='密码')
    sex = models.IntegerField(choices=SEX_CHOICES, default=0, verbose_name='性别')
    img = models.ImageField(upload_to='img', default='img/default.png', verbose_name='头像')
# api/serializers.py文件(需要自己新建)
class UserSerializer(serializers.Serializer):
    # 1. 序列化字段名要与modle中对应的字典名相同
    username = serializers.CharField()
    
    # 2. 自定义序列化字段(SerializerMethodField)
    gender = serializers.SerializerMethodField()
    # 3. get_自定义字段名(self, model_obj) 方法
    def get_gender(self, obj):  # obj为参与序列化的model对象
        return obj.get_sex_display()
    
    # 自定义序列化字段
    icon = serializers.SerializerMethodField()
    def get_icon(self, obj):
        return '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, obj.img)
  1. many=True:群查,传入的user_query含有多个user_obj
  2. many=False:单查,传入的为user_obj,默认为False
# views.py文件
from . import serializers
class UserV2APIView(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            user_obj = models.User.objects.filter(is_delete=False, pk=pk).first()
            if not user_obj:
                return Response({
                    'status': 1,
                    'msg': 'pk error',
                }, status=400)
            
            # 1. 将对象对外提供的字段,以及整个序列化过程封装,形成序列化类
            user_ser = serializers.UserSerializer(user_obj, many=False)  # many默认为False
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': user_ser.data
            })
        else:
            user_query = models.User.objects.filter(is_delete=False).all()
            
            # 2. 将对象对外提供的字段,以及整个序列化过程封装,形成序列化类
            user_ser = serializers.UserSerializer(user_query, many=True)
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': user_ser.data
            })

(二)视图类反序列化过程

  1. 反序列化的字段需要设置条件
  2. reuqired参数:
    • 不设置时,必须参与反序列化
    • False时,前端不提供,则为默认值,提供了则必须进行校验
  3. 自定义校验字段:与系统字段定义方法相同,不能参与入库操作,一般用于全局校验,需要在全局钩子中,将其取出
  4. 局部钩子
    • 命名方法:validate_校验的字段名(self, 字段值value)
    • 校验规则:成功直接返回value,失败抛出校验失败信息ValidationError('错误信息')
  5. 全局钩子
    • 命名方法: validate(self, 所有的校验数据attrs)
    • 校验规则:成功直接返回attrs,失败抛出校验失败信息ValidationError({'异常字段', '错误信息'})
  6. 重写create方法:返回入库成功的对象
    • validated_data:校验后可以入库的数据
  7. 重写update方法:返回入库成功的对象
    • instance:要被修改的对象
    • validated_data:代表校验后用来修改instance的数据
# api/serializers.py文件(需要自己新建)
cla
class UserDeSerializer(serializers.Serializer):
    # 1. 反序列化的字段需要设置条件
    username = serializers.CharField(min_length=3, max_length=16, error_messages={
        'min_length': '太短',
        'max_length': '太长'
    })
    password = serializers.CharField(min_length=3, max_length=16)

    # 2. required=False的字段,前台不提供,走默认值,提供就一定进行校验;不写该字段则采用默认值
    sex = serializers.BooleanField(required=False)

    # 3. 自定义校验字段:与系统字段定义方法相同,不能参与入库操作,一般用于全局校验,需要在全局钩子中,将其取出
    re_password = serializers.CharField(min_length=3, max_length=16)

    # 4. 局部钩子:
    def validate_username(self, value):  # 命名方法:validate_校验的字段名(self, 字段值value)
        if 'g' in value.lower():
            raise serializers.ValidationError('名字中不能有g')  # 失败抛出校验失败信息ValidationError('错误信息')
        return value  #成功返回value

    # 5. 全局钩子:
    def validate(self, attrs):  # 命名方法: validate(self, 所有的校验数据attrs)
        password = attrs.get('password')
        re_password = attrs.pop('re_password')
        if password != re_password:
            raise serializers.ValidationError({'re_password': '两次密码不一致'})  # `ValidationError({'异常字段', '错误信息'})`
        return attrs  # 成功直接返回attrs

    # 6. 重写create方法
    def create(self, validated_data):  # validated_data:校验后可以入库的数据
        return models.User.objects.create(**validated_data)

    # 7. 重写update方法
    def update(self, instance: models.User, validated_data):  # instance:要被修改的对象
        validated_data.pop('username')  # 用户名不能被修改
        models.User.objects.filter(pk=instance.id).update(**validated_data)
        return instance
  1. 调用序列化类的save方法完成入库,Serializer没有提供create和update的实现体(因此需要重写)
  2. 入库得到的user对象需要重新序列化的数据返回给前端,不然密码数据也会传输给前端
# views.py文件
from . import serializers
class UserV2APIView(APIView):
        def post(self, request, *args, **kwargs):
        user_ser = serializers.UserDeSerializer(data=request.data)
        if user_ser.is_valid():
            user_obj = user_ser.save()
            return Response({
                'status': 0,
                'msg': 'ok',
                # 将入库得到的user对象重新序列化的数据返回给前台
                'results': serializers.UserSerializer(user_obj).data  
            })
        else:
            return Response({
                'status': 1,
                'msg': user_ser.errors,
            })

三、ModelSerializer类:模型序列化(核心)

  1. Meta类:序列化类继承ModelSerializer类,所以需要在配置类Meta中进行配置
    • model属性:绑定序列化相关的model表
    • fields属性:采用插拔式设置所有参与序列化和反序列化字段(通过反射)
    • extra_kwargs属性:将系统字段划分为三种
      • read_only为True,序列化,
      • write_only为True,反序列化
      • 不设置:序列化和反序列化都参与
      • required:有默认值的字段为选填字段,为True时为必填字段
  2. 自定义序列化字段:默认就是read_only,且不能修改
    • 第一种:在序列化类中用SerializerMethodField()来实现
    • 第二种:在模型类中用@property来实现,可插拔
  3. 自定义反序列化字段(定义方法和Serializer类相同 )
    • 规则只能在此声明中设置,或是在钩子中设置,在extra_kwargs中对其设置的无效
    • 必须设置 write_only
  4. 局部钩子
    • 命名方法:validate_校验的字段名(self, 字段值value)
    • 校验规则:成功直接返回value,失败抛出校验失败信息ValidationError('错误信息')
  5. 全局钩子
    • 命名方法: validate(self, 所有的校验数据attrs)
    • 校验规则:成功直接返回attrs,失败抛出校验失败信息ValidationError({'异常字段', '错误信息'})
  6. create和update方法不需要再重写,ModelSerializer类已提供,且支持所有关系下的连表操作
class UserModelSerializer(serializers.ModelSerializer):
    # 第一种自定义序列化字段:该字段必须在fields中设置
    # gender = serializers.SerializerMethodField()
    # def get_gender(self, obj):
    #     return obj.get_sex_display()

    # 自定义反序列化字段同Serializer类,且规则只能在此声明中设置,或是在钩子中设置,
    # 在extra_kwargs中对其设置的无效
    # 注:自定义反序列化字段与系统字段,设置规则一样,所以必须设置 write_only
    re_password = serializers.CharField(min_length=3, max_length=16, write_only=True)

    class Meta:
        model = models.User
        # fields采用插拔式设置所有参与序列化与反序列化字段
        fields = ('username', 'gender', 'icon', 'password', 'sex', 're_password')
        extra_kwargs = {
            'username': {  # 系统字段不设置read_only和write_only,默认都参加
                'min_length': 3,
                'max_length': 10,
                'error_messages': {
                    'min_length': '太短',
                    'max_length': '太长'
                }
            },
            'gender': {
                'read_only': True,  # 自定义的序列化字段默认就是read_only,且不能修改,可以省略
            },
            'password': {
                'write_only': True,
            },
            'sex': {  # 有默认值的字段,为选填字段('required': True可以将其变为必填字段)
                'write_only': True,
                # 'required': True
            }
        }


    # 局部全局钩子同Serializer类,是与 Meta 同缩进的
    def validate_username(self, value):
        if 'g' in value.lower():
            raise serializers.ValidationError('名字中不能有g')
        return value

    def validate(self, attrs):
        password = attrs.get('password')
        re_password = attrs.pop('re_password')
        if password != re_password:
            raise serializers.ValidationError({'re_password': '两次密码不一致'})
        return attrs

    # create和update方法不需要再重写,ModelSerializer类已提供,且支持所有关系下的连表操作

四、sys模块之标准三流

输出流和错误流之间异步执行, 谁先抢占到cpu资源谁先打印

  1. 标准输出流:stdout.write, 控制台白色字体打印
  2. 标准输入流:stdin.readline, 获取键盘输入信息,包括换行符
  3. 标准错误流:stderr.write, 控制台红色字体打印
import sys
# 1. 标准输出流
sys.stdout.write('123\n') # == print

# 2. 标准输入流:获取键盘输入信息,包括换行符
res  = sys.stdin.readline()
print(res)

# 3. 标准错误流:控制台红色字体打印  
sys.stderr.write('xyz\n')

猜你喜欢

转载自www.cnblogs.com/wick2019/p/12099032.html
今日推荐