rest_framework校验前端传递过来的字段--ModelSerializer

drf–验证前端传递过来的数据

  • 前端传来的数据先走mixins,然后进行验证,验证通过后,就会调用ModelSerializer的create或者update方法,如果继承的是Serializer,就需要自己重载Serializer中的create或者update方法,或者修改mixins的create等方法的逻辑进行保存。

  • ModelSerializer和ModelForm一样, 验证都是在ModelSerializer和ModelForm里验证

  • views

    from django.contrib.auth import get_user_model
    
    from rest_framework.mixins import CreateModelMixin
    from rest_framework import viewsets
    
    from .serializers import UserRegSerializer
    
    # 获取用户模型类
    UserProfile = get_user_model()
    
    
    class UserViewSet(CreateModelMixin, viewsets.GenericViewSet):
        """
        用户注册
        """
        # 会调用ModelSerializer的create或者update方法,
        # 如果继承的是Serializer,就需要自己重载Serializer中的create或者update方法,或者修改mixins的create等方法的逻辑进行保存
        serializer_class = UserRegSerializer
        queryset = UserProfile.objects.all()
    
  • serializer

    from datetime import datetime
    from datetime import timedelta
    
    from rest_framework import serializers
    # 导入rest_framework的验证器
    from rest_framework.validators import UniqueValidator
    
    from django.contrib.auth import get_user_model
    
    from .models import VerifyCode
    
    UserProfile = get_user_model()
    
    
    class UserRegSerializer(serializers.ModelSerializer):
        # 因为UserProfile里面没有code字段, 所以我们要加个code字段
        # help_text = "验证码" 提示是验证码
        # label 一个简短的文本字符串,可用作HTML表单字段或其他描述性元素中字段的名称。
        # write_only 将其设置True为确保在更新或创建实例时可以使用该字段,但在序列化表示时不包括该字段。 默认为 False
        code = serializers.CharField(required=True, write_only=True, max_length=4, min_length=4, label="验证码",
                                     error_messages={
                                         # 设置每种错误的错误提示
                                         # blank是指为空
                                         "blank": "请输入验证码",
                                         # required是键都没有才会报这个错误
                                         "required": "请输入验证码",
                                         "max_length": "验证码过长",
                                         "min_length": "验证码过短"
                                     },
                                     help_text="验证码")
    
        # allow_blank=False表示不能为空
        username = serializers.CharField(required=True, allow_blank=False, label="用户名",
                                         validators=[UniqueValidator(queryset=UserProfile.objects.all(), message="用户已经存在")])
    
        # 这里的style把密码设置为密文的, 就像input标签type属性设置为password一样
        # write_only 将其设置True为确保在更新或创建实例时可以使用该字段,但在序列化表示时不包括该字段。 默认为 False
        password = serializers.CharField(
            style={'input_type': 'password'}, label="密码", write_only=True,
        )
    
        def create(self, validated_data):
            # 获取到用户对象, 这个对象是继承了AbstractUser的用户对象
            user = super(UserRegSerializer, self).create(validated_data=validated_data)
            # 所以这里有set_password方法
            user.set_password(validated_data["password"])
            # ModelSerializer是有save()方法的, save()方法会调用create函数, 我们在这里重置了create函数, 我们在这里加入里密码设置
            user.save()
            return user
    
        def validate_code(self, code):
            """
            校验验证码
            :param code: 验证码
            :return: 验证码
            """
    
            # 在ModelSerializer前端传递过来的值都会放在initial_data里
    
            # 校验验证码是否存在, 这里一定要排序, 这样才能获取最后的那条记录 这里的username就是mobile
            verify_records = VerifyCode.objects.filter(code=code, mobile=self.initial_data["username"]).order_by("-add_time")
            if verify_records:
                # 获取到最后一条记录
                last_record = verify_records[0]
    
                # 校验验证码是否过期
                # 获取5分钟前的时间  验证码有效期为5分钟
                five_mintes_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
    
                if five_mintes_ago > last_record.add_time:
                    raise serializers.ValidationError("验证码过期")
    
                if last_record.code != code:
                    raise serializers.ValidationError("验证码错误")
    
                # 因为code只做验证, 所以这里不用吧code return回来
            else:
                raise serializers.ValidationError("验证码错误")
    
        def validate(self, attrs):
            """
            校验所有的字段
            :param attrs:  attrs是所有字段组成的字典
            :return: attrs
            """
            # 因为mobile值就是username的值, 所以我们把username的值赋值给mobile
            attrs["mobile"] = attrs["username"]
            # 因为我们不需要code字段了, 所以这里可以直接删除
            del attrs["code"]
            return attrs
    
        class Meta:
            model = UserProfile
            # username必填, 因为UserProfile继承了AbstractUser
            # 模型类写了必填, 你序列化的字段写了这个字段的话, 那么前端必须传这个字段的数据
            fields = (
                "username",
                "code",
                "mobile",
                "password"
            )
    
  • 一般都不会从在serializer下从写create方法, 所以我们应该把从写的create注释掉, 用django的信号机制

  • signals

    # post_save Django中的model对象保存后,自动触发
    from django.db.models.signals import post_save
    from django.dispatch import receiver
    from django.contrib.auth import get_user_model
    
    # 获取用户模型类
    UserProfile = get_user_model()
    
    
    # sender谁传递过来的 接受UserProfile传递过来的
    @receiver(post_save, sender=UserProfile)
    # 在传递过来时它会不是是新建的, 因为update也会传递过来
    # 这里的instance就是我们的UserProfile的对象
    def create_auth_token(sender, instance=None, created=False, **kwargs):
        if created:
            # created为True就代表是新建的
            password = instance.password
            instance.set_password(password)
            instance.save()
    
  • 记住用了django信号机制, 记得在当前应用的apps下写ready方法把写信号机制的文件引入

    from django.apps import AppConfig
    
    
    class UsersConfig(AppConfig):
        name = 'users'
        verbose_name = "用户信息"
    
        def ready(self):
          	# 引入django信号机制所在模块
            import users.signals
    
  • url

    from rest_framework.routers import DefaultRouter
    
    from users.views import UserViewSet
    
    # 生成一个注册器实例对象
    router = DefaultRouter()
    
    # 注册用户
    router.register(r'users', UserViewSet, base_name="users")
    
    urlpatterns = [
        # 自动生成url
        url(r"^", include(router.urls)),
    ]
    
    
  • 效果图
    在这里插入图片描述
    在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

只因为你温柔

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

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

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

打赏作者

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

抵扣说明:

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

余额充值