上一篇文章请点击 django 开发Bug追踪平台之环境搭建篇
web
的app,之后的代码都在这个app里面写python manage.py startapp web
settings.py
文件中注册app,INSTALLED_APPS
添加自己刚才创建的app【默认应该是已经添加了,没有的话自己添加】一下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',
]
static
文件夹中,方便我们以后使用离线文件可以自己去官网下载,也可以拿我这里已经下载好的,我将其放在网盘中,需要可自行下载,其中包含: js、bootstrap、font-awesome【图标】
链接:https://pan.baidu.com/s/1gQRN57XgYcD9y3-Dz8_oaA
提取码:mnjl
解压密码: ruochen666
web
下创建一个用于存放静态文件的 static
文件夹,然后再创建一个 plugin
文件夹,用于存放工具类文件,然后将下载好的 js、bootstrap、font-awesome 放置到 static
文件夹中,结构如下图static
文件夹下的文件为什么要用到母版?
前端页面中,注册和登录的页面基本相似,我们可以让这两个页面都继承自母版,做到代码重用
web
下创建一个 templates
文件夹,在 templates
文件夹下再创建一个 layout
文件夹放我们的母版文件 basic.html
basic.html
代码如下,其中的导航条样式可以直接从 bootstrap官网组件 拿过来修改一下即可
{% load static %}
<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">
<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 navigationspan>
<span class="icon-bar">span>
<span class="icon-bar">span>
<span class="icon-bar">span>
button>
<a class="navbar-brand" href="#">Tracera>
div>
<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="#">Linka>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="#">Actiona>li>
<li><a href="#">Another actiona>li>
<li><a href="#">Something else herea>li>
<li role="separator" class="divider">li>
<li><a href="#">Separated linka>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
】"""MyDjango URL Configuration
The `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 的路由(视图函数我们下面会写)# -*- 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 account
urlpatterns = [
url(r'^register/$', account.register, name='register'), # register
]
web/models.py
文件中创建一个 UserInfo
类,代码如下from django.db import models
class 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
python manage.py makemigrations
python manage.py migrate
views.py
文件删除,创建一个 views
文件夹,方便管理我们的视图,然后在 views
文件夹下创建一个 account.py
文件作为注册视图,代码如下:(RegisterModelForm
和 register.html
后面会写)from django.shortcuts import render
from web.forms.account import RegisterModelForm
def register(request):
form = RegisterModelForm()
return render(request, 'register.html', {'form': form})
web
文件夹下创建一个 forms
文件夹,forms
文件夹中创建 account.py
文件,代码如下
PasswordInput
形式等form-control
样式,前端页面显示比较美观一点code
【验证码】字段# -*- 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 RegexValidator
from 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
文件,代码如下:# -*- 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
文件修改为from django import forms
from django.core.validators import RegexValidator
from 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
表单生成的数据即可{% 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 代码,代码如下{% 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
文件,代码如下.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
中代码如下:from django.conf.urls import url
from web.views import account
urlpatterns = [
url(r'^register/$', account.register, name='register'), # register
url(r'^send/sms/$', account.send_sms, name='send_sms'), # register
]
web/views/account.py
文件中添加代码如下from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from web.forms.account import RegisterModelForm, SendSmsForm
def 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
文件中声明local_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)详细教程
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
文件中,代码如下: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
文件代码如下# -*- 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
#-*- 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
文件import uuid
import hashlib
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)
forms/account.py
文件如下:(只修改了 RegisterModelForm
类的代码,其余不变)from utils import encrypt
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']
def clean_username(self):
username = self.cleaned_data['username']
exists = models.UserInfo.objects.filter(username=username).exists()
if exists:
raise ValidationError('用户名已存在')
# self.add_error('username', '用户名已存在')
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_password(self):
pwd = self.cleaned_data['password']
# 加密 & 返回
return encrypt.md5(pwd)
def clean_confirm_password(self):
# pwd = self.cleaned_data['password']
pwd = self.cleaned_data.get('password')
confirm_pwd = encrypt.md5(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
/login/
页面(登录页面下一篇博文具体介绍)web/views/account.py
文件中代码修改如下:(只修改了 register
函数的内容,其余不变)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})
持续更新中,欢迎大家关注博主