13、Django_rest framework_序列化器和自定

2019-11-15  本文已影响0人  猪儿打滚
一、序列化器中的类属性字段
二、类属性字段的参数
三、反序列化_校验机制
    try:
        # 不符合规则则抛出错误
        serializer.is_valid(raise_exception=True)  
    except Exception as e:
        # 返回序列化器原有的dict类型的错误信息
        return JsonResponse(serializer.errors)
四、rest_framework的校验器(用于validators=校验器

rest_framework.framework中有有多个验证器,这里用其中一个最常见的UniqueValidator唯一验证器示例,更多见:https://juejin.im/post/5aa93246518825555c1d5bba

from rest_framework import serializers
# from login.serializer import UserModelSerializer
from rest_framework.viewsets import ModelViewSet
from login.models import User
from rest_framework.validators import UniqueValidator


class UserSerializer(serializers.Serializer):
  """
    该验证器可用于在模型字段上强制实施 unique=True 约束。它需要一个必需的参数和一个可选的 messages 参数:
                    queryset 必须 - 这是验证唯一性的查询集。
                    message - 验证失败时使用的错误消息。
                    lookup - 用于查找已验证值的现有实例。默认为 'exact'
    """
    name = serializers.CharField(label='用户名', max_length=128, min_length = 10, help_text='用户名',
                                 validators=[
                                     UniqueValidator(
                                         queryset=User.objects.all(),
                                         message="该用户名已存在"
                                     )
                                 ],
                                        error_messages = {
                                            ## 键值对,对应上面的限制条件,以及对应的提示
                                            "max_length":"最长128个字符",
                                            "min_length ":"最短10个字符"
                                        }
)
    password = serializers.CharField(label='账号密码', max_length=256, help_text='账号密码', )
    email = serializers.EmailField(label='账号密码', max_length=128, help_text='账号密码',
                                   allow_null=True, allow_blank=True, default='')
    sex = serializers.CharField(label='账号密码', max_length=128, help_text='账号密码', )
    c_time = serializers.DateTimeField(label='创建时间', help_text='创建时间', read_only=True)
{
  "name": "张三",
  "password": "qw123ssd的",
  "email": "23423@163.com",
  "sex": "男"
}

b.在项目路径使用httpie的命令:http POST http://127.0.0.1:8000/users/ < test/user.json
c.结果:

name重复的结果
五、自定义校验器
def is_unique_user_name(name):
    if '用户' not in name:
        raise serializers,ValidationError('用户名称必须含有“用户”')
    else:
        return name

然后在下面的序列化类中这样调用(看注释):

from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet
from login.models import User
from rest_framework.validators import UniqueValidator

class UserSerializer(serializers.Serializer):

    name = serializers.CharField(label='用户名', max_length=128, help_text='用户名',
                                 validators=[
                                     UniqueValidator(
                                         queryset=User.objects.all(),
                                         message="该用户名已存在"
                                     ), 
                                         is_unique_user_name  # 在这里调用自定义校验器
                                 ])
### 下面内容省略
六、自定义校验字段级别单个字段的校验

如果想要对某个特定的字段机械能自定义的验证规则,那么可以在所写的Serializer子类中,添加validate_<filed_name>的方法来指定自定义该字段的验证

from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet
from login.models import User
from rest_framework.validators import UniqueValidator


class UserSerializer(serializers.Serializer):

    # 自定义字段级别的验证
    def validate_name(self, value):
        """
        用户名需要以“用户”开头
        :return:
        """
        if not str(value).startswith('用户'):
            # 抛出erializers.ValidationError异常
            raise serializers.ValidationError(detail='用户名需要以用户两个字开头')
        # 返回一个验证过的数据
        else:
            return value

    ## 下面内容无需修改
    name = serializers.CharField(label='用户名', max_length=128, help_text='用户名',
                                 validators=[
                                     UniqueValidator(
                                         queryset=User.objects.all(),
                                         message="该用户名已存在"
                                     )
                                 ])
    password = serializers.CharField(label='账号密码', max_length=256, help_text='账号密码', )
    email = serializers.EmailField(label='账号密码', max_length=128, help_text='账号密码',
                                   allow_null=True, allow_blank=True, default='')
    sex = serializers.CharField(label='账号密码', max_length=128, help_text='账号密码', )
    c_time = serializers.DateTimeField(label='创建时间', help_text='创建时间', read_only=True)
七、自定义验证字段级别多个字段的验证

单个字段的校验,走的是validate_<filed_name>方法
多个字段的组合校验,走的是validate方法

    # 自定义多个字段的组合验证规则
    def validate(self, attrs):
        """
        password和email必需含有“lzl”这三个字母
        :return:
        """
        if "lzl" not in attrs['password'] or "lzl" not in attrs['email']:
            raise serializers.ValidationError(detail='password和email必需含有“lzl”这三个字母')
        else:
            return attrs

八、校验器的顺序
九、优化views.py的代码

在之前的代码中,操作数据库的代码是放在views方法中。那么,是否可以放到序列化器中呢?这样在调用序列化器时,就能跟着对数据库进行对应的操作,比如:createupdate操作

1.优化的前提,需了解
2.基于上面,可进行的优化

1.可重写序列化器对象的create()方法,从而优化views.py中的新增方法
2.可重写序列化器对象的update()方法,从而优化views.py中的修改方法

    def create(self, validated_data):
        """
        新增user
        :param validated_data:
        :return:
        """
        return User.objects.create(**validated_data)

    # 如果在创建UserSerializer对象时,传参data和instance,则在调用save()方法时,
    # 实际调用的是序列化器对象中的update()方法
    def update(self, instance, validated_data):
        """
        更新user
        :param instance:
        :param validated_data:
        :return:
        """
        instance.name = validated_data['name']
        instance.password = validated_data['password']
        instance.email = validated_data['email']
        instance.sex = validated_data['sex']
        # instance.c_time = validated_data['c_time']  # 这个字段只读,不进行反序列化,所以注释
        instance.save()
        return instance
class Users(View):

    def post(self, request):
        """V1.3"""
        user_dict = json.loads(request.body.decode('utf8'), encoding='utf8')
        # 实例化序列化器,只给data传值
        serializer = UserSerializer(data=user_dict)
        try:
            serializer.is_valid(raise_exception=True)
        except Exception as e:
            return JsonResponse(serializer.errors)
        serializer.save()  # 这里实际调用的是序列化器的create方法
        return JsonResponse(serializer.data, status=201)

b.修改方法

class UserDetail(View):


    def put(self, request, pk):
        """V1.2"""
        old_user = User.objects.get(id=pk)
        user_dict = json.loads(request.body.decode('utf8'), encoding='utf8')
        # 实例化序列化器,给instance和data传值(instance:需要修改的模型类对象、data:前端传来的修改数据,需进行反序列化和序列化)
        serializer = UserSerializer(instance=old_user, data=user_dict)
        try:
            serializer.is_valid(raise_exception=True)
        except Exception as e:
            raise JsonResponse(serializer.errors)
        serializer.save()  # 实际调用的是序列化器的update方法
        return JsonResponse(serializer.data, status=201)
十、最终代码

ps.这段代码是后来在文中复制粘贴添加的,可能有误

from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet
from login.models import User
from rest_framework.validators import UniqueValidator

    # 自定义校验器
    def is_unique_user_name(name):
        if '用户' not in name:
            raise serializers,ValidationError('用户名称必须含有“用户”')
        else:
            return name

class UserSerializer(serializers.Serializer):
   
    # 自定义单字段级别的验证
    def validate_name(self, value):
        """
        用户名需要以“用户”开头
        :return:
        """
        if "lzl" not in attrs['password'] or "lzl" not in attrs['email']:
            raise serializers.ValidationError(detail='password和email必需含有“lzl”这三个字母')
        else:
            return attrs

    def validate(self, attrs):
        """
        多字段校验
        :param attrs:
        :return:
        """
        if 'tester' not in attrs['tester'] or 'leader' not in attrs['leader']:
            raise serializers.ValidationError('tester需要包含“tester”,leader需要包含“leader”')
        return attrs


    ## 下面内容无需修改
    name = serializers.CharField(label='用户名', max_length=128, help_text='用户名',
                                 validators=[
                                     UniqueValidator(
                                         queryset=User.objects.all(),
                                         message="该用户名已存在"
                                     )
                                 ], 
                                     is_unique_user_name  # 在这里调用自定义校验器
                                 )
    password = serializers.CharField(label='账号密码', max_length=256, help_text='账号密码', )
    email = serializers.EmailField(label='账号密码', max_length=128, help_text='账号密码',
                                   allow_null=True, allow_blank=True, default='')
    sex = serializers.CharField(label='账号密码', max_length=128, help_text='账号密码', )
    c_time = serializers.DateTimeField(label='创建时间', help_text='创建时间', read_only=True)

       自定义多个字段的组合验证规则
    def validate(self, attrs):
        """
        password和email必需含有“lzl”这三个字母
        :return:
        """
        if "lzl" not in attrs['password'] or "lzl" not in attrs['email']:
            raise serializers.ValidationError(detail='password和email必需含有“lzl”这三个字母')
        else:
            return attrs
上一篇 下一篇

猜你喜欢

热点阅读