邮箱注册登录验证 | 模态对话框 | Django开发
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了邮箱注册登录验证 | 模态对话框 | Django开发相关的知识,希望对你有一定的参考价值。
1.创建注册用户表,以及验证码临时表
from django.db import models # 发送邮件临时表:验证码,邮箱,发送次数,当前发送时间 class SendMsg(models.Model): nid = models.AutoField(primary_key=True) code = models.CharField(max_length=6) email = models.CharField(max_length=32, db_index=True) times = models.IntegerField(default=0) ctime = models.DateTimeField() # 模态对话框中用户表;用户名,密码,邮箱,当前注册时间; class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32, unique=True) password = models.CharField(max_length=32) email = models.CharField(max_length=32, unique=True) ctime = models.DateTimeField()
2.注册
① 前端js实现点击获取验证码效果,以及将Form表单返回的错误信息显示到页面
<!-- 点击发送邮件过程中,前端点击的js动态效果,以及请求后端后返回json格式的判断错误信息 --> function BindSendMsg(){ $("#fetch_code").click(function(){ // 点击时,先将整体错误清空 $(‘#register_error_summary‘).empty(); // 获取邮箱输入的值 var email = $(‘#email‘).val(); // 没有填写邮箱,提示错误信息 if(email.trim().length == 0){ // 这个位置有一个div标签,留空给错误信息 $(‘#register_error_summary‘).text(‘请输入注册邮箱‘); return; } // 点击的按钮,添加一个sending样式,‘已发送‘ if($(this).hasClass(‘sending‘)){ // 遇到return下面不再继续执行函数 return; } var ths = $(this); var time = 60; $.ajax({ url: "/send_msg/", type: ‘POST‘, data: {email: email}, dataType: ‘json‘, // arg是后端返回的Json格式的字典,通过字典的值对应判断,执行操作; success: function(arg){ // summary返回统一错误信息,error返回对应错误信息; // {‘status‘: False, "summary": ‘整体错误信息‘, ‘error‘: {}} if(!arg.status){ // 如果后端返回格式错误状态,就将整体错误写到html中; $(‘#register_error_summary‘).text(arg.summary); }else{ // 如果后端返回格式正确状态,表示后台已经发送成功,添加sending样式; ths.addClass(‘sending‘); var interval = setInterval(function(){ ths.text("已发送(" + time + ")"); // 时间倒计时 time -= 1; // 当时间读到0,更新倒计时操作,去掉sending样式状态,重写‘获取验证码‘ if(time <= 0){ // 因为每次点击事件,代码都是从上到下执行, // 所以不需要手动修改返回时间到60秒; clearInterval(interval); ths.removeClass(‘sending‘); ths.text("获取验证码"); } // 1000毫秒,每秒执行一次这个点击事件中的匿名函数; }, 1000); } } }); }); }
② 后端Form表单,验证邮箱格式
from django import forms # 对发送验证码时的表单验证,只验证邮箱 class SendMsgForm(forms.Form): email = forms.EmailField()
③ 点击发送邮箱验证码的后端操作,并做一段时间内注册的次数限制、
# 随机验证码 def random_code(): code = ‘‘ for i in range(4): current = random.randrange(0,4) if current != i: temp = chr(random.randint(65,90)) else: temp = random.randint(0,9) code += str(temp) return code
class BaseResponse: def __init__(self): self.status = False self.code = StatusCodeEnum.Success self.data = None self.summary = None self.message = {}
def send_msg(request): """ 注册时,发送邮箱验证码 :param request: :return: """ rep = BaseResponse() form = SendMsgForm(request.POST) if form.is_valid(): # 如果验证成功,保存正确数据 _value_dict = form.clean() # 取出邮箱作为验证是否已经被注册 email = _value_dict[‘email‘] # 如果用户邮箱已经存在了呢? # 判断用户表中是否含有这个邮箱 # 如果已经存在 has_exists_email = models.UserInfo.objects.filter(email=email).count() if has_exists_email: rep.summary = "此邮箱已经被注册" return HttpResponse(json.dumps(rep.__dict__)) # 获取当前时间 current_date = datetime.datetime.now() # 发送,获取随机获取验证码 code = commons.random_code() # 查看临时表中是否有当前邮箱 count = models.SendMsg.objects.filter(email=email).count() # 如果没有当前邮箱,就添加邮箱 if not count: models.SendMsg.objects.create(code=code, email=email, ctime=current_date) rep.status = True # 如果已经存在当前邮箱,对时间与次数做限制,一个小时只能访问10次 else: # 当前发送时间前一个小时 limit_day = current_date - datetime.timedelta(hours=1) # 查看当前邮箱在一个小时内是否又发送了9次 times = models.SendMsg.objects.filter(email=email, ctime__gt=limit_day, times__gt=9).count() # 如果该邮箱已经超出发送次数限制,就在对象中写入错误提示信息 if times: rep.summary = "‘已超最大次数(1小时后重试)‘" # 否则可以继续发送 else: # 如果上次发送时间距离现在一小时以上就刷新访问字数 unfreeze = models.SendMsg.objects.filter(email=email, ctime__lt=limit_day).count() if unfreeze: models.SendMsg.objects.filter(email=email).update(times=0) from django.db.models import F # 更新验证码与当前时间,访问次数+1 models.SendMsg.objects.filter(email=email).update(code=code, ctime=current_date, times=F(‘times‘) + 1) # 当前处于可以发送状态 rep.status = True else: #error_dict = json.loads(form.errors.as_json()) #rep.summary = error_dict[‘email‘][0][‘message‘] # 表单验证错误,取出错误信息 rep.summary = form.errors[‘email‘][0] return HttpResponse(json.dumps(rep.__dict__))
import smtplib from email.mime.text import MIMEText from email.utils import formataddr def email(email_list, content, subject="标题信息"): msg = MIMEText(content, ‘plain‘, ‘utf-8‘) msg[‘From‘] = formataddr(["来自用户...",‘[email protected]‘]) msg[‘Subject‘] = subject # SMTP服务 server = smtplib.SMTP("[email protected]", 25) # 25表示端口 server.login("[email protected]", "Mic") # 用户名及密码 server.sendmail(‘[email protected]‘, email_list, msg.as_string()) server.quit() # 什么时候执行发送邮箱? # email([‘对方邮箱@qq.com‘, ... ], ‘邮箱发送内容‘)
④ 点击注册(Form表单验证,判断用户名,邮箱是否存在,用户表中写入注册信息)
class RegisterForm(forms.Form): username = forms.CharField() email = forms.EmailField() password = forms.CharField() email_code = forms.CharField()
def register(request): """ 注册 :param request: :return: """ # 创建对象,自动生成验证错误信息等普通字段 rep = BaseResponse() # 创建form对象验证输入信息判断 form = RegisterForm(request.POST) # 如果表单验证成功, if form.is_valid(): current_date = datetime.datetime.now() limit_day = current_date - datetime.timedelta(minutes=1) # 获取表单数据 _value_dict = form.clean() # 超过一分钟,如果没有验证码表示过期 is_valid_code = models.SendMsg.objects.filter(email=_value_dict[‘email‘], code=_value_dict[‘email_code‘], ctime__gt=limit_day).count() if not is_valid_code: rep.message[‘email_code‘] = ‘邮箱验证码不正确或过期‘ return HttpResponse(json.dumps(rep.__dict__)) has_exists_email = models.UserInfo.objects.filter(email=_value_dict[‘email‘]).count() # 判断邮箱是否存在 if has_exists_email: rep.message[‘email‘] = ‘邮箱已经存在‘ return HttpResponse(json.dumps(rep.__dict__)) # 判断用户名是否存在 has_exists_username = models.UserInfo.objects.filter(username=_value_dict[‘username‘]).count() if has_exists_username: rep.message[‘email‘] = ‘用户名已经存在‘ return HttpResponse(json.dumps(rep.__dict__)) # ?????? _value_dict[‘ctime‘] = current_date _value_dict.pop(‘email_code‘) # 当前用户的所有信息 # 将注册信息写入用户表中 obj = models.UserInfo.objects.create(**_value_dict) user_info_dict = {‘nid‘: obj.nid, ‘email‘: obj.email, ‘username‘: obj.username} # 删除临时表中该邮箱数据 models.SendMsg.objects.filter(email=_value_dict[‘email‘]).delete() # 将注册信息写入session表中 request.session[‘is_login‘] = True request.session[‘user_info‘] = user_info_dict rep.status = True # 如果表单验证失败,写入错误信息 else: error_msg = form.errors.as_json() rep.message = json.loads(error_msg) return HttpResponse(json.dumps(rep.__dict__))
3.登录
① 获取验证码,写入session
import random from PIL import Image, ImageDraw, ImageFont, ImageFilter # pip3 install Pillow _letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z _upper_cases = _letter_cases.upper() # 大写字母 _numbers = ‘‘.join(map(str, range(3, 10))) # 数字 init_chars = ‘‘.join((_letter_cases, _upper_cases, _numbers)) def create_validate_code(size=(120, 30), chars=init_chars, img_type="GIF", mode="RGB", bg_color=(255, 255, 255), fg_color=(0, 0, 255), font_size=18, font_type="Monaco.ttf", length=4, draw_lines=True, n_line=(1, 2), draw_points=True, point_chance = 2): ‘‘‘ @todo: 生成验证码图片 @param size: 图片的大小,格式(宽,高),默认为(120, 30) @param chars: 允许的字符集合,格式字符串 @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG @param mode: 图片模式,默认为RGB @param bg_color: 背景颜色,默认为白色 @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF @param font_size: 验证码字体大小 @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf @param length: 验证码字符个数 @param draw_lines: 是否划干扰线 @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效 @param draw_points: 是否画干扰点 @param point_chance: 干扰点出现的概率,大小范围[0, 100] @return: [0]: PIL Image实例 @return: [1]: 验证码图片中的字符串 ‘‘‘ width, height = size # 宽, 高 img = Image.new(mode, size, bg_color) # 创建图形 draw = ImageDraw.Draw(img) # 创建画笔 def get_chars(): ‘‘‘生成给定长度的字符串,返回列表格式‘‘‘ return random.sample(chars, length) def create_lines(): ‘‘‘绘制干扰线‘‘‘ line_num = random.randint(*n_line) # 干扰线条数 for i in range(line_num): # 起始点 begin = (random.randint(0, size[0]), random.randint(0, size[1])) #结束点 end = (random.randint(0, size[0]), random.randint(0, size[1])) draw.line([begin, end], fill=(0, 0, 0)) def create_points(): ‘‘‘绘制干扰点‘‘‘ chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100] for w in range(width): for h in range(height): tmp = random.randint(0, 100) if tmp > 100 - chance: draw.point((w, h), fill=(0, 0, 0)) def create_strs(): ‘‘‘绘制验证码字符‘‘‘ c_chars = get_chars() strs = ‘ %s ‘ % ‘ ‘.join(c_chars) # 每个字符前后以空格隔开 font = ImageFont.truetype(font_type, font_size) font_width, font_height = font.getsize(strs) draw.text(((width - font_width) / 3, (height - font_height) / 3), strs, font=font, fill=fg_color) return ‘‘.join(c_chars) if draw_lines: create_lines() if draw_points: create_points() strs = create_strs() # 图形扭曲参数 params = [1 - float(random.randint(1, 2)) / 100, 0, 0, 0, 1 - float(random.randint(1, 10)) / 100, float(random.randint(1, 2)) / 500, 0.001, float(random.randint(1, 2)) / 500 ] img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲 img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大) return img, strs
def check_code(request): """ 获取验证码 :param request: :return: """ stream = io.BytesIO() # 创建随机字符 code # 创建一张图片格式的字符串,将随机字符串写到图片上 img, code = CheckCode.create_validate_code() img.save(stream, "PNG") # 将字符串形式的验证码放在Session中 request.session["CheckCode"] = code return HttpResponse(stream.getvalue())
② 表单验证
class LoginForm(forms.Form): user = forms.CharField() pwd = forms.CharField() code = forms.CharField()
③ 登录
function SubmitLogin(ths){ $(ths).children(‘:eq(0)‘).addClass(‘hide‘); $(ths).addClass(‘not-allow‘).children(‘:eq(1)‘).removeClass(‘hide‘); // 发送Ajax请求 //完成之后 $(‘#model_login .inp .error‘).remove(); var post_dict = {}; $(‘#model_login input‘).each(function(){ post_dict[$(this).attr("name")] = $(this).val(); }); $.ajax({ url: ‘/login/‘, type: ‘POST‘, data: post_dict, dataType: ‘json‘, success: function(arg){ if(arg.status){ window.location.href = ‘/index‘; }else{ $.each(arg.message, function(k,v){ //<span class="error">s</span> var tag = document.createElement(‘span‘); tag.className = ‘error‘; tag.innerText = v[0][‘message‘]; $(‘#model_login input[name="‘+ k +‘"]‘).after(tag); }) } } }); $(ths).removeClass(‘not-allow‘).children(‘:eq(1)‘).addClass(‘hide‘); $(ths).children(‘:eq(0)‘).removeClass(‘hide‘); }
def login(request): """ 用户登陆 :param request: :return: """ rep = BaseResponse() # 存放消息的类 # 创建登陆的验证表单 form = LoginForm(request.POST) # 如果验证成功 if form.is_valid(): # 获取表单正确数据 _value_dict = form.clean() # 将表单验证码与存在session中单额验证码对比,如果队不上,写入错误信息 if _value_dict[‘code‘].lower() != request.session["CheckCode"].lower(): rep.message = {‘code‘: [{‘message‘: ‘验证码错误‘}]} return HttpResponse(json.dumps(rep.__dict__)) # 如果验证码正确,验证用户名和密码 from django.db.models import Q # ------------------------------------ # models.UserInfo.objects.filter(Q(Q(username=u)&Q(pwd=p))|Q(Q(email=u)&Q(pwd=p))) # 无法动态实现循环操作 # ------------------------------------ con = Q() q1 = Q() q1.connector = ‘AND‘ q1.children.append((‘email‘, _value_dict[‘user‘])) q1.children.append((‘password‘, _value_dict[‘pwd‘])) # 相当于Q(username=u)&Q(pwd=p) q2 = Q() q2.connector = ‘AND‘ q2.children.append((‘username‘, _value_dict[‘user‘])) q2.children.append((‘password‘, _value_dict[‘pwd‘])) # 将q1,q2包裹到一个大Q里; con.add(q1, ‘OR‘) con.add(q2, ‘OR‘) obj = models.UserInfo.objects.filter(con).first() # 如果没有同时满足登陆的条件就写入提示信息 if not obj: rep.message = {‘user‘: [{‘message‘: ‘用户名邮箱或密码错误‘}]} return HttpResponse(json.dumps(rep.__dict__)) # 登入成功,将填写的登录信息写入session中 request.session[‘is_login‘] = True request.session[‘user_info‘] = {‘nid‘: obj.nid, ‘email‘: obj.email, ‘username‘: obj.username} rep.status = True # 如果表单验证失败,写入错误信息 else: error_msg = form.errors.as_json() rep.message = json.loads(error_msg) return HttpResponse(json.dumps(rep.__dict__))
④ 注销登录(清除session)
def logout(request): """ 用户注销 :param request: :return: """ # 用户注销,清除session request.session.clear() return redirect(‘/index/‘)
4.模态对话框HTML页面
<link rel="stylesheet" href="/statics/css/commons.css" /> <link rel="stylesheet" href="/statics/plugins/tab-menu-box/tab.css" />
<div id="accountDialog" class="account-dialog hide clearfix"> <div id="model_login" class="login left"> <div class="header">登陆</div> <div class="content"> <div style="padding: 0 70px"> <div class="tips"> <span>用户名登陆</span> <span style="padding: 0 5px;">|</span> <span>邮箱登陆</span> </div> <div id="login_error_summary" class="error-msg"> </div> <div class="inp"> <input name="user" type="text" placeholder="请输入用户名或邮箱" /> </div> <div class="inp"> <input name="pwd" type="password" placeholder="请输入密码" /> </div> <div class="inp clearfix"> <input name="code" class="check-code" type="text" placeholder="请输入验证码" /> <span> <img class="check-img" src="/check_code/" alt="验证码" onclick="ChangeCode(this);"> </span> </div> <div class="extra"> <input type="checkbox" name="autoLogin" checked="checked" /> <span>一个月内自动登录</span> <a class="right" href="javascript:void(0);">忘记密码?</a> </div> <div class="inp"> <div class="submit" onclick="SubmitLogin(this);"> <span>登陆</span> <span class="hide"> <img src="/statics/images/loader.gif" style="height: 16px;width: 16px"> <span>正在登陆</span> </span> </div> </div> </div> <script> function ChangeCode(ths) { ths.src += ‘?‘; } </script> </div> </div> <div id="model_register" class="register left"> <div class="header"> <span>注册</span> <div class="dialog-close" onclick="CloseDialog(‘#accountDialog‘);">X</div> </div> <div class="content"> <div style="padding: 0 70px"> <div class="tips"> <span>输入注册信息</span> </div> <div id="register_error_summary" class="error-msg"> </div> <div class="inp"> <input name="username" type="text" placeholder="请输入用户名" /> </div> <div class="inp"> <input name="email" id="email" type="text" placeholder="请输入邮箱" /> </div> <div class="inp"> <input name="email_code" class="email-code" type="text" placeholder="请输入邮箱验证码" /> <a id="fetch_code" class="fetch-code" href="javascript:void(0);">获取验证码</a> </div> <div class="inp"> <input name="password" type="password" placeholder="请输入密码" /> </div> <div class="inp"> <div class="submit" onclick="SubmitRegister(this);"> <span>注册</span> <span class="hide"> <img src="/statics/images/loader.gif" style="height: 16px;width: 16px"> <span>正在注册</span> </span> </div> </div> </div> </div> </div> </div>
5.前端JS函数调用
<script type="text/javascript"> $(function () { BindTabMenu(‘#tab-menu-title‘, ‘#tab-menu-body‘); BindLoginRegisterDialog(); BindPublishDialog(); BindSendMsg(); BindNewType(); BindPublishSubmit(); });
以上是关于邮箱注册登录验证 | 模态对话框 | Django开发的主要内容,如果未能解决你的问题,请参考以下文章
Python入门自学进阶-Web框架——16Django登录/注册
Python入门自学进阶-Web框架——16Django登录/注册