DRF 序列化组件单增

自定义序列化(矬)

通常我们后端需要将数据查出来,并返回给需要数据的人,那么就产生了一个序列化的概念

我们可以自定义序列化并返回给客户端。

# 自定义序列化过程
class UserV1View(APIView):
    def get(self,request,*args,**kwargs):
        pk = kwargs.get('pk')
        if pk:
            # 单查
            user_dict = models.User.objects.filter(pk=pk,is_delete=False).values('username','img','sex').first()
            if not  user_dict:
                return Response({'status':1,'msg':'geterror'},status=400)
            user_dict['img'] = '%s%s%s' % (settings.BASE_URL,settings.MEDIA_URL,user_dict.get('img'))
            return Response({'status':0,'msg':'ok','results':user_dict})
        else:
            # 群查
            user_query = models.User.objects.filter(is_delete=False).all().values('username','img','sex')
            user_dict = list(user_query)
            for i in user_dict:
                i['img'] = '%s%s%s' % (settings.BASE_URL,settings.MEDIA_URL,i.get('img'))
            return Response({'status': 0, 'msg': 'ok', 'results': user_dict})

但是这种方式太过于复杂,如果字段多了,不好做拓展,那么我们可以使用DRF提供给我们的方法

Serializer类(方式繁琐)

底层序列化类 UserSerializer

  • 设置序列化字段,并且字段和类型必须和model模型类中一致
  • 如果不参与序列化的字段不写在 UserSerializer 类中
  • 自定义序列化字段,使用 serializers.SerializerMethodField()
api/serializers:
from rest_framework import serializers
from django.conf import settings
from api import models

# 序列化:将数据从后端传给前端
class UserSerializer(serializers.Serializer):
    # 序列化字段
    username = serializers.CharField()
    
    # 自定义序列化字段
    gender = serializers.SerializerMethodField()
    # self:当前对象,obj参与序列化的models模型类对象
    def get_gender(self,obj):
        # 获取性别的映射
        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)

视图序列化步骤

视图CBV方式序列化过程:

  • 视图通过ORM操作得到数据对象
  • 将数据交给定义的序列化类UserSerializer序列化成返回给前台的数据
  • 返回序列化的数据给前台
# DRF 的 Serializer 序列化过程
from api import serializers
class UserV2View(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 Response({'status': 1, 'msg': 'geterror'}, status=400)
            user_dict = serializers.UserSerializer(user_obj,many=False).data
            return Response({'status': 0, 'msg': 'ok', 'results': user_dict})
        else:
            # 群查
            user_query = models.User.objects.filter(is_delete=False).all()
            user_dict = serializers.UserSerializer(user_query,many=True).data
            return Response({'status': 0, 'msg': 'ok', 'results': user_dict})

底层反序列化类 UserCreatSerializer

  • 设置校验的字段,需与model模型类中的字段一致
  • 自定义校验字段和设置的系统校验字段定义没有区别,但是不需要入库(这字段参与全局钩子校验)
  • 所有字段可以设置对应局部钩子校验,校验成功返回value,失败抛异常
  • 所有字段可以设置对应全局钩子校验,校验成功返回attrs,失败抛异常
  • 重写create方法实现增入库,返回入库成功的对象
  • 重写update方法实现改入库,返回入库成功的对象
# 反序列化:将数据从前端传给后端
class UserCreatSerializer(serializers.Serializer):
    # models模型类的字段
    username = serializers.CharField(min_length=3,max_length=8,error_messages={
        'min_length':'用户名太短',
        'max_length':'用户名太长',
        'required':'用户名不能为空',
    })
	
    
    password = serializers.CharField(min_length=3,max_length=8)
    re_password = serializers.CharField(min_length=3,max_length=8)
    # 不写就不参与序列化,写上就必须参与序列化
    # required=False表示可写可不写。前台不提供,走默认值,前提是定义默认值
    sex = serializers.BooleanField(required=False)

    # 局部钩子
    # value:校验的字段数据
    def validate_username(self,value):
        if 'g' in value.lower():
            raise serializers.ValidationError('名字中不能有g')
        return value

    # 全局钩子
    # attrs:所有校验的数据
    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
	
    # 在视图类中调用序列化类的save方法完成入库
    # Serializer虽然有create方法,但具体没有实现,需要重写,因为不知道操作的是哪张表
    def create(self, validated_data):
        return models.User.objects.create(**validated_data)
	
    # instance表示要被修改的对象,validated_data代表校验后修改instance的数据
    def update(self, instance, validated_data):
        validated_data.pop('username')
        models.User.objects.filter(pk=instance.id).update(**validated_data)
        return instance

视图反序列化步骤

  • 从请求对象中获取前台携带的数据包参数
  • 交给反序列化类完成反序列化(data=request.data),实际上是数据的校验
  • 校验成功,借助反序列化类完成数据入库,返回前台入库成功的对象
    def post(self,request,*args,**kwargs):
        user_obj = serializers.UserCreatSerializer(data=request.data)
        if user_obj.is_valid():
            # 入库
            user_obj = user_obj.save()
            return Response({'status':0,'msg':'ok','results':serializers.UserSerializer(user_obj).data})
        else:
            return Response({'status':1,'msg':user_obj.errors})

ModelSerializer类(重点)

序列化与反序列化类 UserModelSerializer

  • 序列化与反序列化类继承ModelSerializer类
  • 在配置类Meta中绑定序列化与反序列化相关的models模型表
  • fields配置,采用插拔式,设置所有参与序列化与反序列化字段
  • extra_kwargs配置,划分字段类型,区分是序列化还是反序列化
    • 序列化只读:read_only
    • 反序列化只写:write_only
    • 两者都可以可读可写:不写
  • 自定义序列化字段,提倡在models模型类中使用@property实现,可插拔
  • 自定义反序列化字段,同Serializer类设置字段即可,且可以在全局钩子校验,在extra_kwargs中设置的此字段类型无效,所以必须设置write_only=True
  • 可以对字段设置局部钩子或者全局钩子,同Serializer类
  • 不需要重写create和update方法,ModelSeializer类已提供

ModelSerializer 序列化类 比Serializer类高级,高级在我们不需要重写create和update方法,并且序列化和反序列化写在同一个类中,使用接口做序列化与反序列化区分就可以了。

# 序列化:将数据从后端传给前端
# 反序列化:将数据从前端传给后端
class UserModelSerializer(serializers.ModelSerializer):
    # 自定义反序列化字段,需要声明write_only,在extra_kwargs中设置校验规则无效
    re_password = serializers.CharField(min_length=3,max_length=8,write_only=True)
    class Meta:
        # 手动设置关联的model模型表
        model = models.User
        # 采用插拔式,设置所有参与序列化与反序列化字段
        fields = ('username','gender','icon','sex','password','re_password')
        extra_kwargs = {
            # 不设置read_only或write_only,默认都参与。
            'username':{
                'min_length':3,
                'max_length':8,
                'error_messages':{
                    'min_length':'太短',
                    'max_length':'太长'
                }
            },
            'icon':{'read_only':True},
            'gender':{'read_only':True},
            'password':{'write_only':True},
            'sex':{'write_only':True}
        }
	
    # 钩子函数同Serializer类中实现方式一样
    def validated_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方法不需要再重写,ModelSeializer类已提供。

视图序列化与反序列化步骤

视图序列化使用的序列化与反序列化类都是同一个定义的UserModelSerializer类

序列化

  • 操作ORM查询数据,返回数据对象
  • 将返回的数据对象传入定义的UserModelSerializer类中,如果是单查,many=False,如果是群差,many=True,返回数据对象
  • 将数据使用Response返回给前台

反序列化

  • 获取请求携带的数据包参数
  • 传入定义的UserModelSerializer类中进行反序列化(data=request.data),实际上是数据的校验
  • 校验成功,借助反序列化类完成数据入库,返回前台入库成功的对象
# DRF 的 ModelSerializer 序列化与反序列化过程
class UserV3View(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 Response({'status': 1, 'msg': 'geterror'}, status=400)
            user_dict = serializers.UserModelSerializer(user_obj,many=False).data
            return Response({'status': 0, 'msg': 'ok', 'results': user_dict})
        else:
            # 群查
            user_query = models.User.objects.filter(is_delete=False).all()
            user_dict = serializers.UserModelSerializer(user_query,many=True).data
            return Response({'status': 0, 'msg': 'ok', 'results': user_dict})

    def post(self,request,*args,**kwargs):
        user_obj = serializers.UserModelSerializer(data=request.data)
        if user_obj.is_valid():
            # 入库
            user_obj = user_obj.save()
            return Response({'status':0,'msg':'ok','results':serializers.UserModelSerializer(user_obj).data})
        else:
            return Response({'status':1,'msg':user_obj.errors})

models模型类中自定义序列化字段

# 自定义序列化字段(插拔式,官方提倡使用)
    @property
    def gender(self):
        return self.get_sex_display()

    @property
    def icon(self):
        from django.conf import settings
        return '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, self.img)

posted @ 2019-12-25 21:56  GeminiMp  阅读(210)  评论(0编辑  收藏  举报