项目预览 👉 Bug追踪平台【云短信买不起了,可通过 手机号:18203503747 密码:ruochen666 登入体验】项目gitee地址 👉 saas
本篇教程对应代码为 【注册验证码处理】提交,可通过对应分支查看
首先,总体的<font color="red">思维导图</font>如下:
web
的app,之后的代码都在这个app里面写```python
python manage.py startapp web
```2.2 app注册settings.py
文件中注册app,INSTALLED_APPS
添加自己刚才创建的app【默认应该是已经添加了,没有的话自己添加】一下```python
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config',
'web.apps.WebConfig',
]
```2.3 母版准备2.3.1 插件引入static
文件夹中,方便我们以后使用离线文件可以自己去官网下载,也可以拿我这里已经下载好的,我将其放在网盘中,需要可自行下载,其中包含: js、bootstrap、font-awesome【图标】
链接:https://pan.baidu.com/s/1gQRN57XgYcD9y3-Dz8_oaA
提取码:mnjl
解压密码: ruochen666web
下创建一个用于存放静态文件的 static
文件夹,然后再创建一个 plugin
文件夹,用于存放工具类文件,然后将下载好的 js、bootstrap、font-awesome 放置到 static
文件夹中,结构如下图
static
文件夹下的文件2.3.2 母版为什么要用到母版?
前端页面中,注册和登录的页面基本相似,我们可以让这两个页面都继承自母版,做到代码重用web
下创建一个 templates
文件夹,在 templates
文件夹下再创建一个 layout
文件夹放我们的母版文件 basic.html
- 结构如下
- `basic.html` 代码如下,其中的导航条样式可以直接从 [bootstrap官网组件](https://v3.bootcss.com/components/#navbar) 拿过来修改一下即可
```html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="{% static '/plugin/bootstrap/css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static '/plugin/font-awesome/css/font-awesome.min.css' %}">
<style>
.navbar-default{
border-radius: 0;
}
</style>
{% block css %}{% endblock %}
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Tracer</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a href="#">产品功能</a></li>
<li><a href="#">企业方案</a></li>
<li><a href="#">帮助文档</a></li>
<li><a href="#">价格</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
{% block content %}{% endblock %}
<script src="{% static 'js/jquery-3.4.1.min.js' %}"></script>
<script src="{% static 'plugin/bootstrap/css/bootstrap.min.css' %}"></script>
{% block js %}{% endblock %}
</body>
</html>
```
MyDjango/MyDjango/urls.py
【我的项目名称为 MyDjango
】 ```python
"""MyDjango URL ConfigurationThe `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^/', include('web.urls')),
]
```
urls.py
文件,用于管理该app 的路由(视图函数我们下面会写) ```python
# -*- coding: UTF-8 -*-
'''=================================================
@Project -> File :MyDjango -> urls
@IDE :PyCharm
@Author :ruochen
@Date :2020/7/2 1:18
@Desc :
=================================================='''
from django.conf.urls import url
from web.views import accounturlpatterns = [
url(r'^register/$', account.register, name='register'), # register
]
```
web/models.py
文件中创建一个 UserInfo
类,代码如下 ```python
from django.db import modelsclass UserInfo(models.Model):
username = models.CharField(verbose_name='用户名', max_length=32)
email = models.EmailField(verbose_name='邮箱', max_length=32)
mobile_phone = models.CharField(verbose_name='手机号', max_length=32)
password = models.CharField(verbose_name='密码', max_length=32)
def __str__(self):
return self.username
```
views.py
文件删除,创建一个 views
文件夹,方便管理我们的视图,然后在 views
文件夹下创建一个 account.py
文件作为注册视图,代码如下:(RegisterModelForm
和 register.html
后面会写) ```python
from django.shortcuts import render
from web.forms.account import RegisterModelFormdef register(request):
form = RegisterModelForm()
return render(request, 'register.html', {'form': form})
```
web
文件夹下创建一个 forms
文件夹,forms
文件夹中创建 account.py
文件,代码如下
- 一: 对字段进行处理,例如手机号进行校验,密码为 PasswordInput
形式等
- 二:给每个字段添加 form-control
样式,前端页面显示比较美观一点
- 三:添加 code
【验证码】字段 ```python
# -*- coding: UTF-8 -*-
'''=================================================
@Project -> File :MyDjango -> account
@IDE :PyCharm
@Author :ruochen
@Date :2020/7/2 12:37
@Desc :
=================================================='''
from django import forms
from django.core.validators import RegexValidatorfrom web import models
class RegisterModelForm(forms.ModelForm):
mobile_phone = forms.CharField(
label='手机号',
validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
password = forms.CharField(
label='密码', widget=forms.PasswordInput())
confirm_password = forms.CharField(
label='重复密码',
widget=forms.PasswordInput())
code = forms.CharField(
label='验证码',
widget=forms.TextInput())
class Meta:
model = models.UserInfo
fields = ['username', 'email', 'password', 'confirm_password', 'mobile_phone', 'code']
def __init__(self, *args, **kwargs):
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-control
属性,之后的代码中其他字段都要用到,每次使用for 循环添加很显然有些赘余,我们可以将其封装在一个类中,这样,需要添加样式的时候直接继承这个类就可以了。web/forms
下创建一个 bootstrap.py
文件,代码如下: ```python
# -*- coding: UTF-8 -*-
'''=================================================
@Project -> File :MyDjango -> bootstrap
@IDE :PyCharm
@Author :ruochen
@Date :2020/7/3 16:25
@Desc :
=================================================='''
class BootStrapForm(object): bootstrap_class_exclude = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
if name in self.bootstrap_class_exclude:
continue
old_class = field.widget.attrs.get('class', '')
field.widget.attrs['class'] = '{} form-control'.format(old_class)
field.widget.attrs['placeholder'] = '请输入{}'.format(field.label,)
```
forms/account.py
文件修改为 ```python
from django import forms
from django.core.validators import RegexValidatorfrom web import models
from web.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='重复密码',
min_length=8,
max_length=64,
error_messages={
'min_length': "重复密码长度不能小于8个字符",
'max_length': "重复密码长度不能大于64个字符"
},
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())
class Meta:
model = models.UserInfo
fields = ['username', 'email', 'password', 'confirm_password', 'mobile_phone', 'code']
```
templates
文件夹下创建 register.html
文件夹,让其继承自 basic.html
form
表单生成的数据即可 ```html
{% extends 'layout/basic.html' %}
{% load static %}{% block title %} 用户注册 {% endblock %}
{% block css %}
<link rel="stylesheet" href="{% static 'css/account.css' %}">
{% endblock %}
{% block content %}
<div class="account">
<div class="title">用户注册</div>
<form id="form" 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">{{ field.errors.0 }}</span>
</div>
<div class="col-xs-5">
<input id="smsBtn" type="button" class="btn btn-default" value="点击获取验证码"/>
</div>
</div>
</div>
{% else %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.lable }}</label>
{{ field }}
<span class="error-msg">{{ field.errors.0 }}</span>
</div>
{% endif %}
{% endfor %}
<div class="row">
<div class="col-xs-3">
<input id="submit" type="button" class="btn btn-primary" value="注 册"/>
</div>
</div>
</form>
</div>
{% endblock %}
{% block js %}
{% endblock %}
```
register.html
中添加js 代码,代码如下 ```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="form" 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 class="row">
<div class="col-xs-3">
<input id="submit" type="button" class="btn btn-primary" value="注 册"/>
</div>
</div>
</form>
</div>
{% endblock %}
{% block js %}
<script>
// 页面框架加载完成之后自动执行函数
$(function () {
bindClickBtnSms();
});
/*
点击获取验证码的按钮绑定事件
*/
function bindClickBtnSms() {
$('#btnSms').click(function () {
$('.error-msg').empty();
// 获取用户输入的手机号
// 找到输入框的ID,根据ID获取值,如何找到手机号的ID?
// Django ModelForm 默认生成字段ID为 “id_ + 字段名”
var mobilePhone = $('#id_mobile_phone').val();
// 发送ajax 请求,把手机号发送过去
$.ajax({
url: "{% url 'send_sms' %}", // 等价于 /send/sms/
type: "GET",
data: {mobile_phone: mobilePhone, tpl: "register"}, // 手机号和注册的模板
dataType: "JSON", // 将服务端返回的数据反序列化为字典
success: function (res) {
// ajax请求发送成功之后,自动执行的函数: res就是后端返回的值
if(res.status) {
sendSmsRemind();
} else {
// 错误信息
// console.log(res); // {status: False, error: { mobile_phone: ["错误信息", ] }
$.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 %}
```
前端页面60s倒计时用到了定时器功能,如下
var obj = setInterval(function(){ // 创建定时器,此处就相当于每1秒执行一次function函数
console.log(123); }, 1000)
clearInterval(obj); // 关闭定时器
那么,对于60s的倒计时功能,我们就可以使用如下代码实现
var time = 60;
var obj = setInterval(function(){
time = time - 1; if(time < 1) { clearInterval(obj); } }, 1000)
account.css
是自己写的css 样式,在 web/static
文件夹下新建一个 css
文件夹用于存放自己写的css 样式,然后新建一个 account.css
文件,代码如下 ```css
.account {
width: 400px;
margin-top: 30px;
margin-left: auto;
margin-right: auto;
border: 1px solid #f0f0f0;
padding: 10px 30px 30px 30px;
-webkit-box-shadow: 5px 10px 10px rgba(0, 0, 0, .05);
box-shadow: 5px 10px 10px rgba(0, 0, 0, .05);
}.account .title {
font-size: 25px;
font-weight: bold;
text-align: center;
}
.account .form-group {
margin-bottom: 20px;
}
```
/send/sms/
,那么我们首先要添加一个 url
, web/urls.py
中代码如下: ```python
from django.conf.urls import url
from web.views import accounturlpatterns = [
url(r'^register/$', account.register, name='register'), # register
url(r'^send/sms/$', account.send_sms, name='send_sms'), # register
]
```
web/views/account.py
文件中添加代码如下 ```python
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from web.forms.account import RegisterModelForm, SendSmsFormdef register(request):
""" 注册 """
form = RegisterModelForm()
return render(request, 'register.html', {'form': form})
def send_sms(request):
""" 发送短信 """
form = SendSmsForm(request, data=request.GET)
# 只是校验手机号:不能为空、格式是否正确
if form.is_valid():
return JsonResponse({'status': True})
return JsonResponse({'status': False, 'error': form.errors})
```
local_settings.py
文件中( local_settings.py
文件的作用,我在上一篇文章中提到过),同时要在 settings.py
文件中声明import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# --------- sms -----------
# 腾讯云短信应用的 app_id
TENCENT_SMS_APP_ID = '自己的app_id'
# 腾讯云短信应用的 app_key
TENCENT_SMS_APP_KEY = '自己的app_key'
# 腾讯云短信签名内容
TENCENT_SMS_SIGN = 'xxxx'
# 短信模板
TENCENT_SMS_TEMPLATE = {
'register': 'xxxx',
'login': 'xxxx',
}关于腾讯云短信的配置,可查看此篇文章:Python 操作腾讯云短信(sms)详细教程local_settings.py
文件配置代码如下小小猿若尘
,如下
settings.py
文件中也要声明如下(settings.py
文件最后添加下面代码,赋值随便填,因为我们在最后导入了 local_settings.py
文件,项目实际上使用的是 local_settings.py
文件中的配置,这里写只是为了声明一下,因为我们的 local_settings.py
文件是不会给别人的)# --------- sms -----------
# 腾讯云短信应用的 app_id
TENCENT_SMS_APP_ID = 6666
# 腾讯云短信应用的 app_key
TENCENT_SMS_APP_KEY = '6666'
# 腾讯云短信签名内容
TENCENT_SMS_SIGN = 'xxxx'
# 短信模板
TENCENT_SMS_TEMPLATE = {
'register': 666666,
'login': 666666,
}django-redis
模块【记得安装】local_settings.py
文件中,代码如下: ```python
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://192.168.1.6:6379", # 在终端中通过 [ipconfig] 命令查看
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {
"max_connections": 1000,
"encoding": 'utf-8'
},
"PASSWORD": "root" # 密码,上述文章有具体说明
}
}
```SendSmsForm
进行了校验,web/forms/account.py
文件中代码如下
- 一:对手机号、短信模板进行了校验
- 二:利用 腾讯云短信 向用户发送短信
- 在项目目录下创建 utils
文件夹,存放我们的工具类,再创建一个 tencent
文件夹,在文件夹下创建 sms.py
文件, 如下:
sms.py
文件代码如下 ```python
# -*- coding: UTF-8 -*-
'''=================================================
@Project -> File :MyDjango -> sms
@IDE :PyCharm
@Author :ruochen
@Date :2020/6/21 15:57
@Desc :
=================================================='''
import ssl
# ssl._create_default_https_context = ssl._create_unverified_context
from qcloudsms_py import SmsMultiSender, SmsSingleSender
from qcloudsms_py.httpclient import HTTPError
from django.conf import settings
def send_sms_single(phone_num, template_id, template_param_list):
"""
单条发送短信
:param phone_num: 手机号
:param template_id: 腾讯云短信模板ID
:param template_param_list: 短信模板所需参数列表,例如:【验证码:{1},描述:{2}】,则传递参数 [888,666]按顺序去格式化模板
:return:
"""
appid = settings.TENCENT_SMS_APP_ID # 自己应用ID
appkey = settings.TENCENT_SMS_APP_KEY # 自己应用Key
sms_sign = settings.TENCENT_SMS_SIGN # 自己腾讯云创建签名时填写的签名内容(使用公众号的话这个值一般是公众号全称或简称)
sender = SmsSingleSender(appid, appkey)
try:
response = sender.send_with_param(86, phone_num, template_id, template_param_list, sign=sms_sign)
except HTTPError as e:
response = {'result': 1000, 'errmsg': "网络异常发送失败"}
return response
def send_sms_multi(phone_num_list, template_id, param_list):
"""
批量发送短信
:param phone_num_list:手机号列表
:param template_id:腾讯云短信模板ID
:param param_list:短信模板所需参数列表,例如:【验证码:{1},描述:{2}】,则传递参数 [888,666]按顺序去格式化模板
:return:
"""
appid = settings.TENCENT_SMS_APP_ID # 自己应用ID
appkey = settings.TENCENT_SMS_APP_KEY # 自己应用Key
sms_sign = settings.TENCENT_SMS_SIGN # 自己腾讯云创建签名时填写的签名内容(使用公众号的话这个值一般是公众号全称或简称)
sender = SmsMultiSender(appid, appkey)
try:
response = sender.send_with_param(86, phone_num_list, template_id, param_list, sign=sms_sign)
except HTTPError as e:
response = {'result': 1000, 'errmsg': "网络异常发送失败"}
return response
```
- 三: 将验证码存入redis数据库中,且超时时间为 60s【即60s后自动消失】,这样我们在提交表单的时候,就可以将用户输入的验证码同redis中存的进行比较,且如果时间超过 60s,用户就要重新获取验证码
- redis的操作可以查看此篇文章: [redis 下载安装 & python 操作redis & django 连接redis](https://blog.csdn.net/qq_29339467/article/details/107920255)
```python
#-*- coding: UTF-8 -*-
'''=================================================
@Project -> File :MyDjango -> account
@IDE :PyCharm
@Author :ruochen
@Date :2020/7/2 12:37
@Desc :
=================================================='''
import random
from django import forms
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django.conf import settings
from django_redis import get_redis_connection
from web import models
from web.forms.bootstrap import BootStrapForm
from utils.tencent.sms import send_sms_single
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='重复密码',
min_length=8,
max_length=64,
error_messages={
'min_length': "重复密码长度不能小于8个字符",
'max_length': "重复密码长度不能大于64个字符"
},
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())
class Meta:
model = models.UserInfo
fields = ['username', 'email', 'password', 'confirm_password', 'mobile_phone', 'code']
class SendSmsForm(forms.Form):
mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
def __init__(self, request, *args, **kwargs):
super().__init__(*args, **kwargs)
self.request = request
def clean_mobile_phone(self):
""" 手机号校验的钩子 """
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('mobile_phone', '短信模板错误')
raise ValidationError('短信模板错误')
# 检验数据库中是否已有手机号
exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
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
```
register.html
文件中js 部分添加点击注册事件函数,代码如下(前面代码部分同上,只是在js 中添加了 bindClickSubmit
函数,并让其在页面框架加载完成后自动执行)ajax请求这里我没有再写一个URL,而是复用了 /register/
,只需要判断用户发的是哪种请求就可以GET
请求,这时我们直接让其跳转到注册页面即可POST
请求,这时我们进行表单验证 & 写入数据库等操作即可{% block js %}
<script>
// 页面框架加载完成之后自动执行函数
$(function () {
bindClickBtnSms();
bindClickSubmit();
});
/*
点击提交(注册)
*/
function bindClickSubmit() {
$('#btnSubmit').click(function () {
$('.error-msg').empty();
// 收集表单中的数据(找到每一个字段)
// 数据通过ajax发送到后台
$.ajax({
url: "{% url 'register' %}",
type: "POST",
data: $('#regForm').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?
// Django ModelForm 默认生成字段ID为 “id_ + 字段名”
var mobilePhone = $('#id_mobile_phone').val();
// 发送ajax 请求,把手机号发送过去
$.ajax({
url: "{% url 'send_sms' %}", // 等价于 /send/sms/
type: "GET",
data: {mobile_phone: mobilePhone, tpl: "register"}, // 手机号和注册的模板
dataType: "JSON", // 将服务端返回的数据反序列化为字典
success: function (res) {
// ajax请求发送成功之后,自动执行的函数: res就是后端返回的值
if (res.status) {
sendSmsRemind();
} else {
// 错误信息
// console.log(res); // {status: False, error: { mobile_phone: ["错误信息", ] }
$.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 %}
utils
文件夹中添加 encrypt.py
文件
from django.conf import settings
def md5(string):
""" MD5加密 """
hash_object = hashlib.md5(settings.SECRET_KEY.encode('utf-8'))
hash_object.update(string.encode('utf-8'))
return hash_object.hexdigest()
def uid(string):
data = "{}-{}".format(str(uuid.uuid4()), string)
return md5(data)
```
- 验证码通过redis 根据手机号(键)获取值与用户输入的进行比较【注意存在过期时间】修改
/login/
页面(登录页面下一篇博文具体介绍)def register(request):
""" 注册 """
if request.method == 'GET':
form = RegisterModelForm()
return render(request, 'register.html', {'form': form})
form = RegisterModelForm(data=request.POST)
if form.is_valid():
# 验证通过,写入数据库(密码要是密文)
# data = form.cleaned_data
# data.pop('code')
# data.pop('confirm_password')
# instance = models.UserInfo.objects.create(**data)
# save() 等同于上述代码,会自动剔除数据库中没有的数据
# 用户表中新建了一条数据(注册)
form.save()
return JsonResponse({'status': True, 'data': '/login/'})
return JsonResponse({'status': False, 'error': form.errors})web/views/account.py
文件中代码修改如下:(只修改了 register
函数的内容,其余不变)持续更新中,欢迎大家关注博主 :smile:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。