Django Rest Framework 电商项目 7-8 DRF实现发送短信验证码接口

发送验证码的过程可以看做是对model设计时的VerifyCode表的操作,是一个created的操作,为了提供这个接口,我们要写相应的ViewSet,在users下的views.py下,我们引入:

from rest_framework.mixins import CreateModelMixin

这个类中有create方法可以重载。

当然还要有:

from rest_framework import viewsets

我们新建的类将继承它们。

即:

class SmsCodeViewSet(CreateModelMixin, viewsets.GenericViewSet):
    """
    发送短信验证码
    """
    pass

要开始写逻辑了,在发送短信(创建验证码记录)之前,我们首先要做三个验证:一是用户输入的是否是合法的手机号,二是手机号是否被注册过,三是同一手机号码的请求频率。我们之前说过,DRF的Serializer和Django中的ModelForm很像,所以验证相关的逻辑我们就放在Serializer中做。在users下新建一个serializers.py,编辑:

from rest_framework import serializers
from django.contrib.auth import get_user_model

import re
from datetime import datetime
from datetime import timedelta

from MxShop.settings import REGEX_MOBILE
from .models import VerifyCode


User = get_user_model()


class SmsSerializer(serializers.Serializer):  # 这里不继承ModelSerializer,因为在model设计时,code是必填字段
    # 如果用了ModelSerializer,就会将表单与VerifyCode做一个关联,则在点击发送验证码时,会报验证码必填的错
    # 所以继承Serializer自己写逻辑进行保存
    mobile = serializers.CharField(max_length=11)  # 有了这个声明,下面就可以针对这个mobile做一些检验了

    def validate_mobile(self, mobile):
        """
        验证手机号码
        """

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

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

        # 验证码发送频率
        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

并在settings.py中新增:

#手机号码正则表达式
REGEX_MOBILE = "^1[358]\d{9}$|^147\d{8}$|^176\d{8}$"

有了这个serializer,我们就可以完成SmsCodeViewSet了。在users/views.py中,引入刚刚的serializer:

from .serializers import SmsSerializer

然后在SmsCodeViewSet中添加一句:

serializer_class = SmsSerializer

这样以后,我们完成了手机号的验证,就可以开始进行create操作了。点进我们继承的CreateModelMixin中,我们重载它的create方法,拷贝它到SmsCodeViewSet中,并修改为(大家可以看看下面的与原来的有什么不同):

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)  # 拿到上边的serializer
        serializer.is_valid(raise_exception=True)  # 这里如果=True,这一步如果出错,直接抛异常,不会进入下面的代码行;这里is_valid出错,返回400

        mobile = serializer.validated_data["mobile"]  # 上面已经验证了,能跑到这一步,所以mobile一定是有的
        yun_pian = YunPian(APIKEY)
        code = self.generate_code()
        sms_status = yun_pian.send_sms(code=code, mobile=mobile)  # 返回的是re_dict,可以点进去看看
        # 下面来解析这个变量
        if sms_status["code"] != 0:  # 返回的status代表的含义可以看一看云片网的文档
            return Response({
                "mobile":sms_status["msg"]  # msg中放的是云片网错误信息
            }, status=status.HTTP_400_BAD_REQUEST)
        else:
            code_record = VerifyCode(code=code, mobile=mobile)
            code_record.save()
            return Response({
                "mobile":mobile
            }, status=status.HTTP_201_CREATED)  # 成功后返回的是手机号

引入引用的外部文件:

from rest_framework.response import Response
from rest_framework import status

from utils.yunpian import YunPian
from MxShop.settings import APIKEY
from .models import VerifyCode

为此我们还要写一个生成验证码的方法,依旧是在SmsCodeViewSet中,添加一个方法:

    def generate_code(self):
        """
        生成四位数字的验证码
        """
        seeds = "1234567890"  # 种子
        random_str = []
        for i in range(4):
            random_str.append(choice(seeds))

        return "".join(random_str)  # 原本是一个数组

引入:

from random import choice

我们现在可以来调试一下,在create方法中打断点。然后要给它注册一个url,在根urls中,添加:

router.register(r'code', SmsCodeViewSet, base_name="code")

from users.views import SmsCodeViewSet

这个时候访问codes页面,发现GET方法不被允许。

但底下又出现了一个post框,我们可以输入mobile然后POST(之前的login页面也可以,相当于postman了)。可以先输入错误格式的手机号,看看错误提示:

首先是是http status,然后错误信息是以键值对的形式展示的,键为出错字段的名称,值为数组,列出了所有的错误。

你可能感兴趣的:(Django Rest Framework 电商项目 7-8 DRF实现发送短信验证码接口)