06-day04-短信登录

一、短信登录

  • 使用与注册相同的短信发送接口

1.1、页面展示

  • 第一步 :设计短信登录路由
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/urls.py 
"""Bug_manager URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.conf.urls import url, include
from web_app.views import account

urlpatterns = [
    url(r'^send/sms/', account.send_sms, name='send_sms'),
    # 短信登录
    url(r'^login/sms', account.login_sms, name='login_sms'),
    url(r'^register/', account.register, name='register'),
]
  • 第二步 :视图,目前仅用于测试
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/views/account.py 
...
...
from web_app.forms.account import RegisterModelForm,SendSmsForm, LoginSMSForm
...
...

def login_sms(request):
    """ 短信登录 """
    form = LoginSMSForm()
    return render(request, 'login_sms.html', {'form': form})
  • 第三步 :为短信登录,编写一个用于数据校验的 Form
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/forms/account.py 

from django import forms
from web_app import models
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django.conf import settings
from django_redis import get_redis_connection
import random
from utils.tencent.sms import send_sms_single


class RegisterModelForm(forms.ModelForm):
    password = forms.CharField(label='密码',
                               min_length=8,
                               max_length=64,
                               error_messages={
                                   "min_length": "密码长度不能小于8个字符",
                                   "max_length": "密码长度不能大于64个字符",
                               },
                               widget=forms.PasswordInput())
    confirm_password = forms.CharField(label='重复密码', widget=forms.PasswordInput())
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
    code = forms.CharField(label='验证码', widget=forms.TextInput())

    #  model 定义元数据
    class Meta:
        # 对应的Model类
        model = models.UserInfo
        # Model类中哪些字段可以展示,__all__ 表示所有
        # fields = '__all__' 也表示默认的展示顺序,可以手动指定展示顺序
        fields = ['username', 'email', 'password', 'confirm_password', 'mobile_phone', 'code']

    def __init__(self, *args, **kwargs):
        """
        重写RegisterModelForm 的 初始化方法
            name  表示字段名称
            field 表示forms.CharField对象
                code = forms.CharField(label='验证码', widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': "请输入验证码"}))
        """
        super(RegisterModelForm, self).__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = "请输入{}".format(field.label)

    def clean_username(self):
        """
        用户名校验的钩子函数
        """
        username = self.cleaned_data['username']
        exists = models.UserInfo.objects.filter(username=username).exists()
        if exists:
            raise ValidationError('用户名已存在')
        return username

    def clean_email(self):
        """
        邮箱校验的钩子函数
        """
        email = self.cleaned_data['email']
        exists = models.UserInfo.objects.filter(email=email).exists()
        if exists:
            raise ValidationError('邮箱已存在')
        return email

    def clean_confirm_password(self):
        """
        密码和确认密码对比校验
        """
        pwd = self.cleaned_data['password']
        confirm_pwd = self.cleaned_data['confirm_password']
        if pwd != confirm_pwd:
            raise ValidationError('两次密码不一致')
        return confirm_pwd

    def clean_mobile_phone(self):
        """
        手机号校验钩子函数
        """
        mobile_phone = self.cleaned_data['mobile_phone']
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            raise ValidationError('手机号已注册')
        return mobile_phone

    def clean_code(self):
        code = self.cleaned_data['code']
        # mobile_phone = self.cleaned_data['mobile_phone']
        mobile_phone = self.cleaned_data.get('mobile_phone')
        if not mobile_phone:
            return code

        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError('验证码失效或未发送,请重新发送')
        redis_str_code = redis_code.decode('utf-8')
        if code.strip() != redis_str_code:
            raise ValidationError('验证码错误,请重新输入')
        return code

class SendSmsForm(forms.Form):
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'),])

    # 重写__init__ 仅为在views视图调用Form初始化函数式多传递request参数
    def __init__(self, request, *args, **kwargs):
        super(SendSmsForm, self).__init__(*args, **kwargs)
        self.request = request

    def clean_mobile_phone(self):
        """手机号校验钩子函数 (单个字段方法如 def cleand_字段名())"""
        mobile_phone = self.cleaned_data['mobile_phone']
        # 判断短信模板是否有问题
        tpl = self.request.GET.get('tpl')
        template_id = settings.TENCENT_SMS_TEMPLATE.get(tpl)
        if not template_id:
            # self.add_error('短信模板错误')
            raise ValidationError('短信模板错误')

        # 校验数据库是否存在
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            # self.add_error('手机号已存在')
            raise ValidationError('手机号已存在')

        # 发短信
        code = random.randrange(1000, 9999)
        sms = send_sms_single(mobile_phone, template_id, [code, ])
        if sms['result'] != 0:
            raise ValidationError('短信发送失败,{}'.format(sms['errmsg']))

        # 验证码redis(django-redis)
        conn = get_redis_connection()
        conn.set(mobile_phone, code, ex=60)

        return mobile_phone

class LoginSMSForm(forms.Form):
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
    code = forms.CharField(label='验证码', widget=forms.TextInput())

    def __init__(self, *args, **kwargs):
        """
        重写RegisterModelForm 的 初始化方法
            name  表示字段名称
            field 表示forms.CharField对象
                code = forms.CharField(label='验证码', widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': "请输入验证码"}))
        """
        super(LoginSMSForm, self).__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = "请输入{}".format(field.label)


  • 第三步 :短信登录页面视图
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/login_sms.html 
{% extends 'layout/basic.html' %}
{% load static %}

{% block title %} 用户短信登录 {% endblock %}

{% block css %}
    <link rel="stylesheet" href="{% static 'css/account.css' %}">
    <style>
        .error-msg {
            color: red;
            position: absolute;
            font-size: 13px;
        }
    </style>
{% endblock %}


{% block content %}
    <div class="account">
        <div class="title">用户短信登录</div>
        <form id="smsForm" method="POST" novalidate>
            {% csrf_token %}
            {% for field in form %}
                {% if field.name == 'code' %}
                    <div class="form-group">
                        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                        <div class="row">
                            <div class="col-xs-7">
                                {{ field }}
                                <span class="error-msg"></span>
                            </div>
                            <div class="col-xs-5">
                                <input id="btnSms" type="button" class="btn btn-default" value="点击获取验证码">
                            </div>
                        </div>
                    </div>
                {% else %}
                    <div class="form-group">
                        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                        {{ field }}
                        <span class="error-msg"></span>
                    </div>
                {% endif %}
            {% endfor %}
{#            <div>#}
{#                <div style="float: right;">#}
{#                    <a href="{% url 'login' %}">用户名密码登录?</a>#}
{#                </div>#}
{#            </div>#}
            <div class="row">
                <div class="col-xs-3">
                    <input id="btnSubmit" type="button" class="btn btn-primary" value="登  录"/>
                </div>
            </div>
        </form>
    </div>
{% endblock %}


{% block js %}
    <script>
        // 页面框架加载完成之后自动执行函数
        $(function () {
            bindClickBtnSms();
            bindClickSubmit();
        });

        /*
        点击登录
        */
        function bindClickSubmit() {
            $('#btnSubmit').click(function () {
                $('.error-msg').empty();
                // 收集表单中的数据(找到每一个字段)$('#regForm').serialize()
                // 数据ajax发送到后台
                $.ajax({
                    url: "{% url 'login_sms' %}",
                    type: "POST",
                    data: $('#smsForm').serialize(), // 所有字段数据 + csrf token
                    dataType: "JSON",
                    success: function (res) {
                        if (res.status) {
                            location.href = res.data;
                        } else {
                            $.each(res.error, function (key, value) {
                                $("#id_" + key).next().text(value[0]);
                            })
                        }
                    }
                })
            })
        }

        /*
       点击获取验证码的按钮绑定事件
        */
        function bindClickBtnSms() {
            $('#btnSms').click(function () {

                $('.error-msg').empty();

                // 获取用户输入的手机号
                // 找到输入框的ID,根据ID获取值,如何找到手机号的那个ID?
                var mobilePhone = $('#id_mobile_phone').val();

                // 发送ajax请求,把手机号发送过去
                $.ajax({
                    url: "{% url 'send_sms' %}", // 等价于 /send/sms/
                    type: "GET",
                    data: {mobile_phone: mobilePhone, tpl: "login"},
                    dataType: "JSON", // 将服务端返回的数据反序列化为字典
                    success: function (res) {
                        // ajax请求发送成功之后,自动执行的函数; res就是后端返回的值
                        if (res.status) {
                            sendSmsRemind();
                        } else {
                            // 错误信息
                            // console.log(res); // {status:False, error:{ mobile_phone: ["错误信息",],code: ["错误信息",] }  }
                            $.each(res.error, function (key, value) {
                                $("#id_" + key).next().text(value[0]);
                            })
                        }
                    }
                })

            })
        }

        /*
        倒计时
         */
        function sendSmsRemind() {
            var $smsBtn = $('#btnSms');
            $smsBtn.prop('disabled', true); // 禁用
            var time = 60;
            var remind = setInterval(function () {
                $smsBtn.val(time + '秒重新发送');
                time = time - 1;
                if (time < 1) {
                    clearInterval(remind);
                    $smsBtn.val('点击获取验证码').prop('disabled', false);
                }
            }, 1000)

        }
    </script>
{% endblock %}
  • 查看页面效果

image

  • 第四步 :优化 Form 中注册及短信登录的__init__ BootStrap 中共有的前端样式,编写成一个基类,其他用到 BootStrap样式的Form也继承此基类;
# 定义BootStrap基类
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/forms/bootstrap.py 

class BootStrapForm(object):
    def __init__(self, *args, **kwargs):
        """
        重写RegisterModelForm 的 初始化方法
            name  表示字段名称
            field 表示forms.CharField对象
                code = forms.CharField(label='验证码', widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': "请输入验证码"}))
        """
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = "请输入{}".format(field.label)
# Form 中 用到 BootStrap 属性的就继承BootStrap基类

(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/forms/account.py  
from django import forms
from web_app import models
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django.conf import settings
from django_redis import get_redis_connection
import random
from utils.tencent.sms import send_sms_single
from web_app.forms.bootstrap import BootStrapForm

class RegisterModelForm(BootStrapForm, forms.ModelForm):
    password = forms.CharField(label='密码',
                               min_length=8,
                               max_length=64,
                               error_messages={
                                   "min_length": "密码长度不能小于8个字符",
                                   "max_length": "密码长度不能大于64个字符",
                               },
                               widget=forms.PasswordInput())
    confirm_password = forms.CharField(label='重复密码', widget=forms.PasswordInput())
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
    code = forms.CharField(label='验证码', widget=forms.TextInput())

    #  model 定义元数据
    class Meta:
        # 对应的Model类
        model = models.UserInfo
        # Model类中哪些字段可以展示,__all__ 表示所有
        # fields = '__all__' 也表示默认的展示顺序,可以手动指定展示顺序
        fields = ['username', 'email', 'password', 'confirm_password', 'mobile_phone', 'code']

    def clean_username(self):
        """
        用户名校验的钩子函数
        """
        username = self.cleaned_data['username']
        exists = models.UserInfo.objects.filter(username=username).exists()
        if exists:
            raise ValidationError('用户名已存在')
        return username

    def clean_email(self):
        """
        邮箱校验的钩子函数
        """
        email = self.cleaned_data['email']
        exists = models.UserInfo.objects.filter(email=email).exists()
        if exists:
            raise ValidationError('邮箱已存在')
        return email

    def clean_confirm_password(self):
        """
        密码和确认密码对比校验
        """
        pwd = self.cleaned_data['password']
        confirm_pwd = self.cleaned_data['confirm_password']
        if pwd != confirm_pwd:
            raise ValidationError('两次密码不一致')
        return confirm_pwd

    def clean_mobile_phone(self):
        """
        手机号校验钩子函数
        """
        mobile_phone = self.cleaned_data['mobile_phone']
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            raise ValidationError('手机号已注册')
        return mobile_phone

    def clean_code(self):
        code = self.cleaned_data['code']
        # mobile_phone = self.cleaned_data['mobile_phone']
        mobile_phone = self.cleaned_data.get('mobile_phone')
        if not mobile_phone:
            return code

        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError('验证码失效或未发送,请重新发送')
        redis_str_code = redis_code.decode('utf-8')
        if code.strip() != redis_str_code:
            raise ValidationError('验证码错误,请重新输入')
        return code

class SendSmsForm(forms.Form):
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'),])

    # 重写__init__ 仅为在views视图调用Form初始化函数式多传递request参数
    def __init__(self, request, *args, **kwargs):
        super(SendSmsForm, self).__init__(*args, **kwargs)
        self.request = request

    def clean_mobile_phone(self):
        """手机号校验钩子函数 (单个字段方法如 def cleand_字段名())"""
        mobile_phone = self.cleaned_data['mobile_phone']
        # 判断短信模板是否有问题
        tpl = self.request.GET.get('tpl')
        template_id = settings.TENCENT_SMS_TEMPLATE.get(tpl)
        if not template_id:
            # self.add_error('短信模板错误')
            raise ValidationError('短信模板错误')

        # 校验数据库是否存在
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            # self.add_error('手机号已存在')
            raise ValidationError('手机号已存在')

        # 发短信
        code = random.randrange(1000, 9999)
        sms = send_sms_single(mobile_phone, template_id, [code, ])
        if sms['result'] != 0:
            raise ValidationError('短信发送失败,{}'.format(sms['errmsg']))

        # 验证码redis(django-redis)
        conn = get_redis_connection()
        conn.set(mobile_phone, code, ex=60)

        return mobile_phone

class LoginSMSForm(BootStrapForm, forms.Form):
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
    code = forms.CharField(label='验证码', widget=forms.TextInput())

1.2、点击发送短信

  • 第一步 :短信登录页面,点击获取验证码前端绑定事件,将前端的信息发送到后端;
    • 注意的是登录的短信验证码码模板tlp=login
{% block js %}
    <script>
        // 页面框架加载完成之后自动执行函数
        $(function () {
            bindClickBtnSms();
            bindClickSubmit();
        });

        /*
        点击登录
        */
        function bindClickSubmit() {
            $('#btnSubmit').click(function () {
                $('.error-msg').empty();
                // 收集表单中的数据(找到每一个字段)$('#regForm').serialize()
                // 数据ajax发送到后台
                $.ajax({
                    url: "{% url 'login_sms' %}",
                    type: "POST",
                    data: $('#smsForm').serialize(), // 所有字段数据 + csrf token
                    dataType: "JSON",
                    success: function (res) {
                        if (res.status) {
                            location.href = res.data;
                        } else {
                            $.each(res.error, function (key, value) {
                                $("#id_" + key).next().text(value[0]);
                            })
                        }
                    }
                })
            })
        }

        /*
       点击获取验证码的按钮绑定事件
        */
        function bindClickBtnSms() {
            $('#btnSms').click(function () {

                $('.error-msg').empty();

                // 获取用户输入的手机号
                // 找到输入框的ID,根据ID获取值,如何找到手机号的那个ID?
                var mobilePhone = $('#id_mobile_phone').val();

                // 发送ajax请求,把手机号发送过去
                $.ajax({
                    url: "{% url 'send_sms' %}", // 等价于 /send/sms/
                    type: "GET",
                    data: {mobile_phone: mobilePhone, tpl: "login"},
                    dataType: "JSON", // 将服务端返回的数据反序列化为字典
                    success: function (res) {
                        // ajax请求发送成功之后,自动执行的函数; res就是后端返回的值
                        if (res.status) {
                            sendSmsRemind();
                        } else {
                            // 错误信息
                            // console.log(res); // {status:False, error:{ mobile_phone: ["错误信息",],code: ["错误信息",] }  }
                            $.each(res.error, function (key, value) {
                                $("#id_" + key).next().text(value[0]);
                            })
                        }
                    }
                })

            })
        }

        /*
        倒计时
         */
        function sendSmsRemind() {
            var $smsBtn = $('#btnSms');
            $smsBtn.prop('disabled', true); // 禁用
            var time = 60;
            var remind = setInterval(function () {
                $smsBtn.val(time + '秒重新发送');
                time = time - 1;
                if (time < 1) {
                    clearInterval(remind);
                    $smsBtn.val('点击获取验证码').prop('disabled', false);
                }
            }, 1000)

        }
    </script>
{% endblock %}
  • 第二步 :数据校验,当使用短信验证码登录时,则不需要像此前注册 Form 钩子函数中手机号校验此前必须没有,短信登录而是需要校验数据库中已经存在此手机号,表示此前已经注册过;
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/forms/account.py 
...
...
class SendSmsForm(forms.Form):
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'),])

    # 重写__init__ 仅为在views视图调用Form初始化函数式多传递request参数
    def __init__(self, request, *args, **kwargs):
        super(SendSmsForm, self).__init__(*args, **kwargs)
        self.request = request

    def clean_mobile_phone(self):
        """手机号校验钩子函数 (单个字段方法如 def cleand_字段名())"""
        mobile_phone = self.cleaned_data['mobile_phone']
        # 判断短信模板是否有问题
        tpl = self.request.GET.get('tpl')
        template_id = settings.TENCENT_SMS_TEMPLATE.get(tpl)
        if not template_id:
            # self.add_error('短信模板错误')
            raise ValidationError('短信模板错误')
        # 校验数据库是否存在
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if tpl == 'login':
            if not exists:
                # self.add_error('手机号已存在')
                raise ValidationError('手机号不存在')
        else:
            # 校验手机号是否存在
            if exists:
                raise ValidationError('手机号已存在')

        # 发短信
        code = random.randrange(1000, 9999)
        sms = send_sms_single(mobile_phone, template_id, [code, ])
        if sms['result'] != 0:
            raise ValidationError('短信发送失败,{}'.format(sms['errmsg']))

        # 验证码redis(django-redis)
        conn = get_redis_connection()
        conn.set(mobile_phone, code, ex=60)

        return mobile_phone
...
...

image

1.3、点击登录

  • 第一步 :前端 将登陆按钮绑定事件,获取表单数据发送到后台;
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/templates/login_sms.html 
...
...
           <div class="row">
                <div class="col-xs-3">
                    <input id="btnSubmit" type="button" class="btn btn-primary" value="登  录"/>
                </div>
            </div>
        </form>
    </div>
{% endblock %}


{% block js %}
    <script>
        // 页面框架加载完成之后自动执行函数
        $(function () {
            bindClickBtnSms();
            bindClickSubmit();
        });

        /*
        点击登录
        */
        function bindClickSubmit() {
            $('#btnSubmit').click(function () {
                $('.error-msg').empty();
                // 收集表单中的数据(找到每一个字段)$('#regForm').serialize()
                // 数据ajax发送到后台
                $.ajax({
                    url: "{% url 'login_sms' %}",	// http://localhost/web_apps/login/sms
                    type: "POST",
                    data: $('#smsForm').serialize(), // 所有字段数据 + csrf token
                    dataType: "JSON",
                    success: function (res) {
                        if (res.status) {
                            location.href = res.data;
                        } else {
                            $.each(res.error, function (key, value) {
                                $("#id_" + key).next().text(value[0]);
                            })
                        }
                    }
                })
            })
        }
...
...
  • 第二步 :后端视图接收到POST请求后进行表单校验
  • 方式一 (代码使用):
# Form
class LoginSMSForm(BootStrapForm, forms.Form):
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
    code = forms.CharField(label='验证码', widget=forms.TextInput())

    def clean_mobile_phone(self):
        """手机号校验钩子函数"""
        mobile_phone = self.cleaned_data['mobile_phone']
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if not exists:
            raise ValidationError("手机号不存在")

    def clean_code(self):
        """验证码校验钩子函数"""
        code = self.cleaned_data['code']
        mobile_phone = self.cleaned_data.get('mobile_phone')
        # 如果没有手机号则不进行校验
        if not mobile_phone:
            return code

        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError('验证码失效或未发送,请重新发送')
        redis_str_code = redis_code.decode('utf-8')
        if code.strip() != redis_str_code:
            raise ValidationError('验证码错误,请重新输入')
        return code
  • 方式二 :
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/forms/account.py 
...
...

class LoginSMSForm(BootStrapForm, forms.Form):
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
    code = forms.CharField(label='验证码', widget=forms.TextInput())

    def clean_mobile_phone(self):
        """手机号校验钩子函数"""
        mobile_phone = self.cleaned_data['mobile_phone']
        user_objects = models.UserInfo.objects.filter(mobile_phone=mobile_phone).first()
        if not user_objects:
            raise ValidationError("手机号不存在")
        return user_objects # 返回用户对象

    def clean_code(self):
        """验证码校验钩子函数"""
        code = self.cleaned_data['code']
        # mobile_phone = self.cleaned_data.get('mobile_phone')
        user_objects = self.cleaned_data.get('mobile_phone')
        # 如果没有手机号则不进行校验
        if not user_objects:
            return code

        conn = get_redis_connection()
        redis_code = conn.get(user_objects.mobile_phone)
        if not redis_code:
            raise ValidationError('验证码失效或未发送,请重新发送')
        redis_str_code = redis_code.decode('utf-8')
        if code.strip() != redis_str_code:
            raise ValidationError('验证码错误,请重新输入')
        return code

...
...
# views视图
(Bug_manager) daizhe@daizhedeMacBook-Pro Bug_manager % cat web_app/views/account.py 
...
...
def send_sms(request):
    # 校验方法一
    # mobile_phone = request.GET.get('mobile_phone')
    # tpl = request.GET.get('tpl')

    # 校验方法二 将前端数据数据使用Form校验,SendSmsForm中定义的仅校验手机号
    form = SendSmsForm(request, data=request.GET)
    # is_valid 只是校验手机号,不能为空、格式正确
    if form.is_valid():
        return JsonResponse({'status': True})

    return JsonResponse({'status': False, 'error': form.errors })

def login_sms(request):
    """ 短信登录 """
    if request.method == 'GET':
        form = LoginSMSForm()
        return render(request, 'login_sms.html', {'form': form})

    form = LoginSMSForm(request.POST)
    if form.is_valid():
        # 用户输入正确,登录成功
        user_objects = form.cleaned_data['mobile_phone']

        return JsonResponse({'status': True, 'data': "/index/"})
    return JsonResponse({"status": False, 'error': form.errors})

...
...

image

posted @ 2021-07-04 19:56  SRE运维充电站  阅读(284)  评论(0编辑  收藏  举报