DRF实现注册

一、功能描述:

用户提交手机号,获取验证码,输入密码后,注册并登录。

二、发送短信验证码

1、首先要校验手机号是否合法,是否已经注册,还要限制发送验证码不能过于频繁。

# 发送短信序列化
class SmsSerializer(serializers.Serializer):
    mobile = serializers.CharField(max_length=11)

    def validate_mobile(self, mobile):  # validate_字段  验证
        """
        验证手机号码
        :param data:
        :return:
        """

        # 手机是否注册
        if User.objects.filter(mobile=mobile).count():
            raise serializers.ValidationError("用户已经存在")

        # 验证手机号码是否合法
        if not re.match(REGEX_MOBILE, mobile):
            raise serializers.ValidationError("手机号码非法")

        # 验证码发送频率,60秒发一次
        one_mintes_ago = datetime.now() - timedelta(hours=0, minutes=1, seconds=0)
        if VerifyCode.objects.filter(add_time__gt=one_mintes_ago, mobile=mobile).count():
            raise serializers.ValidationError("距离上一次发送未超过60s")

        return mobile

定义一个工具类,向验证码服务商发送请求:

import json
import requests


class YunPian(object):
    def __init__(self, api_key):
        self.api_key = api_key
        self.single_send_url = "https://sms.yunpian.com/v2/sms/single_send.json"

    def send_sms(self, code, mobile):
        """
        :param code: 验证码
        :param mobile:  手机号
        :return:  
        """
        params = {
            "apikey": self.api_key,
            "mobile": mobile,
            "text": "您的验证码是{code}.".format(code=code)
        }

        response = requests.post(self.single_send_url, data=params)
        re_dict = json.loads(response)
        return re_dict

视图类,发送验证码的功能:

class SmsCodeViewset(CreateModelMixin, viewsets.GenericViewSet):
    # 发送短信验证码
    serializer_class = SmsSerializer

    # 要发送验证码,生成四位验证码
    def get_code(self):
        seeds = '1234567890'  # 随机种子
        random_str = []
        for i in range(4):
            random_str.append(choice(seeds))
        return "".join(random_str)

    # 重写create方法,向短信服务网站发起请求
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)  # 出现错误,直接抛出异常,不会向下执行

        mobile = serializer.validated_data['mobile']  # validated_data 获取数据
        # 发短信
        yun_pian = YunPian(APIKEY)
        code = self.get_code()

        sms_status = yun_pian.send_sms(code=code, mobile=mobile)  # sms_status得到返回的状态
        if sms_status["code"] != 0:
            return Response({
                "mobile": sms_status["msg"]
            }, status=status.HTTP_400_BAD_REQUEST)
        else:
            # 保存验证码
            code_record = VerifyCode(code=code, mobile=mobile)
            code_record.save()
            return Response({
                "mobile": sms_status["msg"]
            }, status=status.HTTP_201_CREATED)  # 成功

三、注册

1、序列化类

class UserRegSerializer(serializers.ModelSerializer):
    code = serializers.CharField(required=True, write_only=True, max_length=4, min_length=4, label='验证码',
                                 error_messages={
                                     'blank': '请输入验证码',
                                     'required': '请输入验证码',
                                     'max_length': '验证码格式错误',
                                     'min_length': '验证码格式错误'
                                 }, help_text='验证码')
    username = serializers.CharField(label='用户名', help_text='用户名', required=True, allow_blank=False,
                                     validators=[UniqueValidator(queryset=User.objects.all(), message='用户已存在')])
    password = serializers.CharField(
        style={'input_type': 'password'}, help_text='密码', label='密码', write_only=True,
    )  # write_only 数据不返回来

    def validate_code(self, code):
        """
        对验证码就行检验
        :param code:
        :return:
        """
        verify_records = VerifyCode.objects.filter(mobile=self.initial_data['username']).order_by('-add_time')
        # initial_data 用户传过来的值都在这里面
        if verify_records:
            # 如果用户多次发送,取出最新验证码
            last_record = verify_records[0]
            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('验证码错误')
        else:
            raise serializers.ValidationError('验证码错误')

    def validate(self, attrs):  #全局校验
        attrs['mobile'] = attrs['username']
        del attrs['code']  # 不会保存到数据库中,多余字段,到这已经通过code校验,可以删除
        return attrs

    class Meta:
        model = User
        fields = ('username', 'code', 'mobile', 'password')

2、视图类

class UserViewset(CreateModelMixin, viewsets.GenericViewSet):
    """
    用户注册
    """
    serializer_class = UserRegSerializer
    queryset = User.objects.all()

    def create(self, request, *args, **kwargs):
        #重写create方法
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = self.perform_create(serializer)  # 保存

        re_dict = serializer.data
        payload = jwt_payload_handler(user)
        re_dict["token"] = jwt_encode_handler(payload)  # 获取token
        re_dict["name"] = user.name if user.name else user.username
        #返回浏览器保存,不保存在服务器

        headers = self.get_success_headers(serializer.data)
        return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)

    def get_object(self):
        return self.request.user

    def perform_create(self, serializer):
        return serializer.save()

3、Django信号

在保存用户信息时,密码会保存成明文,所以引入了Django信号量机制。

from django.dispatch import receiver
from django.contrib.auth import get_user_model

User = get_user_model()


@receiver(post_save, sender=User)  # 用户提交的数据即将保存时,对密码加密
def create_user(sender, instance=None, created=False, **kwargs):
    if created:
        password = instance.password
        instance.set_password(password)
        instance.save()

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值