drf框架中的Serializer序列化组件

03-01 Serializer组件

1.定义序列化器

在Django REST framework中如果想为某个模型类提供一个序列化器,需要自定义一个类,然后继承rest_framework.serializers.Serializer。

序列化类:

# serializers.py
from rest_framework import serializers

# 序列化类
class UserSerializer(serializers.Serializer):
    # 注意:参与序列化的字段必须跟模型类中的字段同名
    name = serializers.CharField()
    age = serializers.IntegerField()
    # DecimalField字段需要提供如下两个参数
    height = serializers.DecimalField(max_digits=5, decimal_places=2)
    
    # 自定义序列化字段,序列化的属性值由方法来提供,
    # 方法的名字:固定为get_属性名,
    # 方法的参数:(系列化对象, 序列化的model对象)
    # 自定义序列化字段名不要和model中已有的属性重名
    gender = serializers.SerializerMethodField()
    def get_gender(self, obj):
        return obj.get_sex_display

反序列化类:

# serializers.py    
# 反序列化类
class UserDeserializer(serializers.Serializer):
    # 反序列化属性名不是必须与model属性名对应,但是与之对应会方便序列化将校验通过的数据与数据库进行交互
    name = serializers.CharField(min_length=3, max_length=6, errormessages={
        'required': '姓名不能为空',
        'min_length': '姓名不能少于3位'
    })
    ...
    # 系统可选的反序列化字段:没有提供不进行校验(数据库中有默认值或者可以为空),提供了就进行校验
    age = serializers.IntegerField(min_value=0, max_value=100, requied=False)
    # 自定义反序列化字段:一定参与校验,且要在校验过程中,将其从入库的数据中取出,剩余与model对应的数据才会入库
    re_pwd = serializers.CharField(min_length=3, max_length=11)
    
    # 自定义校验规则:局部钩子,全局钩子
    # 局部钩子:validate_字段名(self, 字段值)
    # 规则:成功返回value,失败抛异常
    def validate_name(self, value):
        if '#' in value:
            raise serializers.ValidationError('名字含有非法字符')
        return value
    
    # 全局钩子:validate(self, 所有校验的数据字典)
    # 规则:成功返回attrs, 失败抛异常
    def validate(self, attrs):
        # 取出联合校验的字段们:不需要入库的从校验字段中取出
        pwd = attrs.get('pwd')
        # 从attrs中移除re_pwd,方便剩余数据入库
        re_pwd = attrs.pop('re_pwd')
        if pwd != re_pwd:
            raise serializers.ValidationError({'re_pwd': '两次密码不一致'})
        return attrs
    
    # 添加数据需要重写create方法
    from . import models
    def create(self, validated_data):
        return models.User.objects.create(**validated_data)

视图类使用序列化类序列化数据:

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from . import models, serializers

class UserAPIView(APIView):
    # 单查群查
    def get(self, request, *args, **kwargs):
        """
        1. ORM操作数据库拿到资源数据
        2. 格式化成能够返回给前台的数据(序列化)
        3. 返回格式化后的数据给前台
        """
        pk = kwargs.get('pk')
        if pk:
            user_obj = models.User.objects.filter(pk=pk).first()
            if notuser_obj:
                return Response({'status': 1, 'msg': 'error'})
            
            # 完成序列化
            user_ser = serializers.UserSerializer(user_obj)
            user_data = user_ser.data
            return Response({
                'status': 0, 'msg': '单查 ok',
                'results': user_data,
            })
        
        # 群查
        user_query = models.User.objects.all()
        # 完成序列化,当传入多个对象的时候需要指定参数many=True
        user_list_data = serialiazers.UserSerializer(user_query, many=True)
        return Response({
            'status': 0, 'msg': '群查 ok',
            'results': user_list_data
        })

视图类使用反序列化类反序列化数据:

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from . import models, serializers

class UserAPIView(APIView):
    # 单增
    def post(self, request, *args, **kwargs):
        """
        1. 从请求对象中拿到前台的数据
        2. 校验前台数据是否合法
        3. 反序列化成后台Model对象与数据库交互
        """
        request_data = request.data
        
        # 反序列化的目的:封装数据的校验过程,以及与数据库交互的过程
        # 注意:反序列化需要将数据传给data参数
        user_ser = serializers.UserDeserializer(data=request_data)
        # 调用反序列化的校验规则:系统规则,自定义规则(局部钩子,全局钩子)
        # 这里类似Django的forms组件中的is_valid()方法
        result = user_ser.is_valid()
        
        if result:
            # 校验通过,与数据库进行交互: 增(create),改(update)
            user_obj = user_ser.save()
            return Response({
                'status': 0, 'msg': 'OK',
                # 调用序列化类,将新建的对象序列化并返回给前端
                'results': serializers.UserSerializer(user_obj).data
            })
        else:
            # 校验失败, 返回错误信息
            return Response({
                'status': 1,
                'msg': user_ser.errors
            }, status=400)

2.总结

序列化:

"""
一、视图类的三步操作
1. ORM操作数据库拿到资源数据
2. 格式化(序列化)成能够返回给前端的数据类型
3. 返回格式化后的数据给前端

二、视图类的序列化操作
1. 直接将要序列化的数据传给序列化类
2. 要序列化的数据如果是单个对象,序列化的参数many为False,如果是多个,many为True

三、序列化类
1. model类中要返回给前台的字段,在序列化类中要进行声明,属性名必须与model的字段名相同,且Field类型也要保持一致
2. model类中不需要返回给前台的字段,在序列化类中不需要声明(省略)
3. 自定义序列化字段用SerializerMethodField()作为字段类型,该字段的值来源于 get_自定义字段命(self, obj)方法的返回值
""" 

反序列化:

"""
一、视图类的三步操作
1. 从请求对象中拿到前台的数据
2. 校验前台的数据是否合法
3. 反序列化成后台Model对象与数据库交互

二、视图类的反序列化操作
1. 将要反序列化的数据传给反序列化类的data参数
2. 要反序列化的数据如果是个单个字典,反序列化类的参数many=False,多个many=True

三、反序列化类
1. 系统的字段,可以在Field类型中设置系统校验规则(name=serializers.CharField(min_length=3))
2. required校验规则决定该字段是否需要校验(默认required为True,数据库字段有默认值或可以为空的字段required可以赋值为False,不写不校验)
3. 自定义的反序列化字段,设置系统校验规则同系统字段,但需要在自定义校验规则中(局部、全局钩子)将自定义反序列化字段取出(返回剩余的数据与数据库交互)
4. 局部钩子的方法命名:validate_属性名(self, value) 失败抛异常,成功返回value
5. 全局钩子的方法命名:validate(self, attrs) 失败抛异常,成功返回attrs
"""
posted @ 2019-11-20 19:43  17vv  阅读(356)  评论(0编辑  收藏  举报