【DRF配置管理】如何使用序列化和反序列化:验证码、注册和登录

原文作者:我辈李想
版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。

DRF应用和管理

【DRF配置管理】Django安装DRF框架并生成openapi风格文档
【DRF配置管理】如何实现JWT身份验证
【DRF配置管理】如何使用序列化:验证码、注册和登录
【DRF配置管理】如何结合ORM实现排序、模糊搜索、范围查询
【DRF配置管理】如何在视图类使用get_objects()
【DRF配置管理】如何实现RBAC页面菜单和按钮权限
【DRF配置管理】如何建立coreapi风格api接口文档
【DRF配置管理】如何建立swagger风格api接口文档



前言

通常使用drf框架,都会使用序列化能力,尤其是ModelSerializer序列化。通过序列化我们可以实现字段的验证、文档的注释、异常获取等。
在这里插入图片描述


一、序列化

1.serializers序列化

使用serializers时,必须重写create和update方法
class BitableRecordsSerializer(serializers.Serializer):
    email = serializers.EmailField()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

    def create(self, validated_data):
        return BitableRecords.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.email = validated_data.get('email', instance.email)
        instance.content = validated_data.get('content', instance.content)
        instance.created = validated_data.get('created', instance.created)
        return instance

2.ModelSerializer序列化

class HistoryDataSerializer(ModelSerializer):
    """
    目标区域
    """

    class Meta:
        model = HistoryData
        fields = '__all__'

3.Meta参数

class HistoryDataSerializer(ModelSerializer):
    """
    目标区域
    """

    class Meta:
        model = HistoryData
        fields = '__all__'
        read_only_fields = ['pic_id',]  # 只读字段
		# extra_kwargs = {'password': {'write_only': True}}

4.选择字段的序列化

方式一

class HistoryDataSerializer(ModelSerializer):
    """
    目标区域
    """
    gender = serializers.CharField(source='get_gender_display')  # 根据source数据来源定义字段

    class Meta:
        model = HistoryData
        fields = '__all__'  
        read_only_fields = ['pic_id', ]
        # extra_kwargs = {'password': {'write_only': True}}

方式二

class HistoryData(models.Model):
	
	def get_gender(self):
		return self.get_gender_display()

class HistoryDataSerializer(ModelSerializer):
    """
    目标区域
    """
    gender = serializers.CharField(source='get_gender')  # 根据source数据来源定义字段

    class Meta:
        model = HistoryData
        fields = '__all__'  # fields = ['gender',...]
        read_only_fields = ['pic_id', ]
        # extra_kwargs = {'password': {'write_only': True}}

方式三

class HistoryDataSerializer(ModelSerializer):
    """
    目标区域
    """
    gender = serializers.SerializerMethodField()

	def get_gender(self,obj):
		return obj.get_gender_display()

    class Meta:
        model = HistoryData
        fields = '__all__'  # fields = ['gender',...]
        read_only_fields = ['pic_id', ]
        # extra_kwargs = {'password': {'write_only': True}}

如果models的字段是使用models.TextChoices作为选项,需要自己实现get_gender方法。

5.时间字段序列化

import pytz

class HistoryDataSerializer(ModelSerializer):
    """
    目标区域
    """
    # imaging_time 将时间转为utc时间,并且按照%Y-%m-%d %H:%M:%S格式输出字符串
    imaging_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', default_timezone=pytz.timezone('UTC'))
    
    class Meta:
        model = HistoryData
        fields = '__all__'  # fields = ['imaging_time ',...]
        read_only_fields = ['pic_id', ]
        # extra_kwargs = {'password': {'write_only': True}}

6.to_representation验证返回

class HighScore(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    player_name = models.CharField(max_length=10)
    score = models.IntegerField()


class HighScoreSerializer(serializers.BaseSerializer):
    def to_representation(self, instance):
        return {
            'score': instance.score,
            'player_name': instance.player_name
        }
	# def to_representation(self, instance):
	#     """Convert `username` to lowercase."""
	#     ret = super().to_representation(instance)
	#     ret['username'] = ret['username'].lower()
	#     return ret

views.py调用

serializer = BitableRecordsSerializer(queryset, many=True)
   return Response(status=status.HTTP_200_OK,
                  data={'code': 0,
                        'msg': 'ok',
                        'data': serializer.data})

二、反序列化

1.错误验证信息和国际化

    default_error_messages = {
        "username_error": _('用户名必须以字母开头,且包含3~15个字母、数字'),
        "username_registered_error": _('用户名已存在'),
        'password_error': _('两次输入密码不一致'),
        "phone_error": _('手机号格式有误,请重填'),
        "phone_registered_error": _('手机号已注册'),
        'code_error': _('验证码不正确'),
        "email_error": _('电子邮箱格式有误,请重填'),
        "email_registered_error": _('邮箱已注册'),
    }

2.Meta参数

    class Meta:
        model = LoginUser
        fields = ['username', 'phone', 'password', 'password2', 'code']
        read_only_fields = ['pic_id',]
		# extra_kwargs = {'password': {'write_only': True}}  

3.字段验证

serializers和ModelSerializer序列化也是反序列化,支持序列化字段验证,ModelSerializer将启用models的字段验证。

class RegisterSerializer(ModelSerializer):
    """注册账户"""
    password = serializers.CharField(write_only=True)
    password2 = serializers.CharField(write_only=True)
    code = serializers.IntegerField(write_only=True)

    class Meta:
        model = LoginUser
        fields = ['username', 'phone', 'password', 'password2', 'code']
class RegisterSerializer(ModelSerializer):
    """注册账户"""
	username = serializers.CharField(required=True, allow_blank=False, label="用户名", max_length=16, min_length=6,validators=[UniqueValidator(queryset=User.objects.all(),message="用户已经存在")],error_messages={"blank": "用户名不允许为空",
	                  "required": "请输入用户名",
	                  "max_length": "用户名长度最长为16位",
	                   "min_length": "用户名长度至少为6位"})

注:ModelSerializer反序列化创建信息时,如需接收 null值和空字符串,Model序同时指定null=True, blank=True, 其中null处理null,blank处理空字符串‘’

4.单字段方法验证

	    def validate_email(self, email):
	        """单字段验证:邮箱"""
	        # 1.邮箱格式
	        rs = '^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'
	        if not re.match(rs, email):
	            raise serializers.ValidationError(self.error_messages['email_error'])
	        # 2.邮箱是否存在
	        if LoginUser.objects.filter(email=email).exists():
	            raise serializers.ValidationError(self.error_messages['email_registered_error'])
	        return email

5.组合字段方法验证

	    def validate(self, attrs):
	        """组合字段验证"""
	        password = attrs.get('password')
	        password2 = attrs.get('password2')
	        if password and password2 and password != password2:
	            raise serializers.ValidationError(self.error_messages['password_error'])
	        attrs['password'] = make_password(attrs['password2'])  # 还可以通过重写create方法加密密码
	        # 验证码
	        phone = attrs.get('phone')
	        code = attrs.get('code')
	        if cache.has_key(phone):
	            old_code = cache.get(phone)
	            if str(old_code) != str(code):
	                raise serializers.ValidationError(self.error_messages['code_error'])
	        else:
	            raise serializers.ValidationError(self.error_messages['code_error'])
	        del attrs['password2']
	        del attrs['code']
	        return attrs

样例内容

class RegisterSerializer(ModelSerializer):
    """注册账户"""
    password = serializers.CharField(write_only=True)
    password2 = serializers.CharField(write_only=True)
    code = serializers.IntegerField(write_only=True)

    default_error_messages = {
        "username_error": _('用户名必须以字母开头,且包含3~15个字母、数字'),
        "username_registered_error": _('用户名已存在'),
        'password_error': _('两次输入密码不一致'),
        "phone_error": _('手机号格式有误,请重填'),
        "phone_registered_error": _('手机号已注册'),
        'code_error': _('验证码不正确'),
        "email_error": _('电子邮箱格式有误,请重填'),
        "email_registered_error": _('邮箱已注册'),
    }

    class Meta:
        model = LoginUser
        fields = ['username', 'phone', 'password', 'password2', 'code']

    def validate_username(self, username):
        """单字段验证:名字"""
        # 1.用户名格式
        if not re.match(r'^[a-zA-z]\w{2,15}$', username):
            raise serializers.ValidationError(self.error_messages['username_error'])
        # 2.用户名是否存在
        if LoginUser.objects.filter(username=username).exists():
            raise serializers.ValidationError(self.error_messages['username_registered_error'])
        return username

    def validate_phone(self, phone):
        """单字段验证:手机号"""
        # 1.验证手机号码是否合法
        rs = r'^([+]?0?\d{2,3}-?|\([+]?0?\d{2,3}\)|\([+]?0?\d{2,3}\))?\d+$|^([+]?0?\d{2,3}-?|\([+]?0?\d{2,3}\)|\([+]?0?\d{2,3}\))?[1-9]\d{4,10}(-\d{1,10})?$'
        if not re.match(r'1[0-9]\d{9}$', str(phone)) and not re.match(rs, str(phone)):
            raise serializers.ValidationError(self.error_messages['phone_error'])
        # 2.手机是否注册
        if LoginUser.objects.filter(phone=str(phone)).exists():
            raise serializers.ValidationError(self.error_messages['phone_registered_error'])
        return phone

    # def validate_code(self, code):
    #     """单字段验证:验证码"""
    #     phone =
    #     if cache.has_key(phone):
    #         old_code = cache.get(phone)
    #         print(str(code))
    #         print(1111)
    #         print(str(old_code))
    #         if str(old_code) != str(code):
    #             raise serializers.ValidationError(self.error_messages['code_error'])

    def validate_email(self, email):
        """单字段验证:邮箱"""
        # 1.邮箱格式
        rs = '^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'
        if not re.match(rs, email):
            raise serializers.ValidationError(self.error_messages['email_error'])
        # 2.邮箱是否存在
        if LoginUser.objects.filter(email=email).exists():
            raise serializers.ValidationError(self.error_messages['email_registered_error'])
        return email

    def validate(self, attrs):
        """组合字段验证"""
        password = attrs.get('password')
        password2 = attrs.get('password2')
        if password and password2 and password != password2:
            raise serializers.ValidationError(self.error_messages['password_error'])
        attrs['password'] = make_password(attrs['password2'])  # 还可以通过重写create方法加密密码
        # 验证码
        phone = attrs.get('phone')
        code = attrs.get('code')
        if cache.has_key(phone):
            old_code = cache.get(phone)
            if str(old_code) != str(code):
                raise serializers.ValidationError(self.error_messages['code_error'])
        else:
            raise serializers.ValidationError(self.error_messages['code_error'])
        del attrs['password2']
        del attrs['code']
        return attrs
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我辈李想

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值