BBS仿博客系统 登录功能
先看登录功能的需求:
三个输入框,分别是用户名,密码,验证码,输入错误能够直接把错误显示出来且不刷新整个页面,验证码输入框旁边是一个显示验证码的图片,如果看不清,可以点一下就更换图片,登录成功后跳转到主页
先将页面大致搭建出来
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css"> <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script> </head> <body> <div class="container-fluid"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h2 class="text-center">登录</h2> <div class="form-group"> <label for="id_username">用户名</label> <input type="text" name="username" id="id_username" class="form-control"> </div> <div class="form-group"> <label for="id_username">密码</label> <input type="text" name="password" id="id_password" class="form-control"> </div> <div class="form-group"> <label for="id_username">验证码</label> <div class="row"> <div class="col-md-6"> <input type="text" name="code" id="id_code" class="form-control"> </div> <div class="col-md-6"> <img src="/get_code/" alt="" width="310" height="35" id="id_img"> </div> </div> </div> <button class="btn btn-success" id="id_button">登录</button> <span class="errors" style="color: red" id="id_error"></span> </div> </div> </div> </body> </html>
具体效果
写动态验证码
img标签的src可以写url,可以写文件本地路径,也可以写文件二进制
pillow模块
from PIL import Image,ImageDraw,ImageFont
img标签src可以写二进制
打开本地文件发送二进制数据
with open(r'D:\fullstack_s4\BBS\avatar\002_wLZfWbk.jpg','rb') as f:
data = f.read()
return HttpResponse(data)
这样也将图片发到img标签里了
这里我们就像如果有一个模块可以为我们动态生成二进制图片就好了,发现还真有,pillow模块
pillow模块
from PIL import Image,ImageDraw,ImageFont
生成一个图片
img_obj = Image.new('RGB',(310,35),'green') # 第三个参数既可以传颜色英文也可以传rgb参数
img_obj = Image.new('RGB',(310,35),(128,128,128)) # 第三个参数既可以传颜色英文也可以传rgb参数
生成一个画笔
img_draw = ImageDraw.Draw(img_obj) # 你的画笔就可以在该图片上写字,花线,打点等
生成一个字典对象
img_font = ImageFont.truetype('static/font/mo.ttf',35)#字体直接百度ttf下载
在图片上写字
img_draw.text((60+i*45,0),temp_code,get_random(),img_font)#temp_code是我们写的验证码的五位随机数
生成一个BytesIO对象
io_obj = BytesIO() # 将这个对象看成文件句柄
img_obj.save(io_obj,'png') # 将图片数据存入内存管理器中 需要指定图片格式
return HttpResponse(io_obj.getvalue()) # 将保存的数据以二进制的数据返回出来
def get_random(): return random.randint(0,255),random.randint(0,255),random.randint(0,255) def get_code(request): img_obj = Image.new('RGB',(310,35),get_random()) img_draw = ImageDraw.Draw(img_obj) img_font = ImageFont.truetype('static/font/mo.ttf',35) code = '' for i in range(5): random_int = str(random.randint(0,9)) random_lower = chr(random.randint(97,122)) random_upper = chr(random.randint(65,90)) temp_code=random.choice([random_int,random_lower,random_upper]) img_draw.text((60+i*45,0),temp_code,get_random(),img_font) code += temp_code print(code) request.session['code'] = code io_obj = BytesIO() img_obj.save(io_obj,'png') return HttpResponse(io_obj.getvalue()
效果图
这样就是实现了刷新网页随机刷新验证码,但我们要的是不刷新网页,直接点验证码图片也可以刷新
我们发现img标签的src只要改变就会自动刷新
$('#id_img').click(function () { // 获取图片src旧的路径 let oldPath = $(this).attr('src'); // 修改图片的src属性 $(this).attr('src',oldPath + '?') });
前端提交数据到后端
因为输入错误时,需要将其显示出来,并且只局部刷新,所以需要用ajax提交
<script> $('#id_img').click(function () { let old_src = $(this).attr('src'); $(this).attr('src',old_src + '.') }); $('#id_button').click(function () { $.ajax({ url:'', type:'post', data:{ 'username':$('#id_username').val(), 'password':$('#id_password').val(), 'code':$('#id_code').val(), 'csrfmiddlewaretoken':'{{ csrf_token }}' }, success:function (data) { if (data.code == 100){ location.href = data.url } else { $('#id_error').html(data.msg) } } }) }) </script>
后端接收数据并校验
前端发送过来的数据有四组键值对,username,password,code,csrfmiddlewaretoken,
前端ajax还有个回调函数需要接受数据,先定义一个back_dic={'code':100,'msg':''}
先对code验证码做校验,这样可以减少数据库的压力,然后再对用户,密码做校验,根据校验的结果不同多back_dic赋不同的值
最后校验完成后返回前端时,return JsonResponse(back_dic),JsonRespongse能直接将字典转成二进制发到前端,由ajax回调函数接收并渲染。
def login(request): back_dic={'code':100,'msg':''} if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') code = request.POST.get('code') if request.session.get('code').upper() == code.upper(): user_obj = auth.authenticate(username=username,password=password) if user_obj: # 登录成功记录当前用户状态 auth.login(request,user_obj) back_dic['msg'] = '登录成功' back_dic['url'] = '/home/' else: back_dic['code'] = 102 back_dic['msg'] = '用户名或密码错误' else: back_dic['code'] = 103 back_dic['msg'] = '验证码错误' return JsonResponse(back_dic) return render(request,'login.html')
主页导航条
主页在没登录时,显示登录,注册,已登录则显示用户名,头像,和更多操作
为实现这个效果我们需要做一个if判断,这里我们只要知道request在前端也可以用就很容易
<ul class="nav navbar-nav navbar-right"> {% if request.user.is_authenticated %}#判断,已登陆返回True,未登录返回False <li><a href="#">{{ request.user.username }}</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多操作 <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="/set_password/">修改密码</a></li> <li><a href="#">修改头像</a></li> <li role="separator" class="divider"></li> <li><a href="/logout/">注销</a></li> </ul> </li> {% else %} <li><a href="/register/">注册</a></li> <li><a href="/login/">登录</a></li> {% endif %} </ul>
退出登录
def logout(request): auth.logout(request)#auth真好用 return redirect('/home/')
修改密码
四个输入框,用户名,旧密码,新密码,确认新密码
在主页进入修改密码时,要能直接获取用户名字,并且不能修改,但是如果直接访问url的话就获取不到用户名,所以我们可以做一个登录认证。
修改密码不需要局部刷新,直接用form提交数据就行,后端收到后先校验旧密码,在校验两次密码输入一致,
所有检验都成功后直接跳转到登录界面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css"> <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script> </head> <body> <div class="container-fluid"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h2 class="text-center">修改密码</h2> <form action="" method="post"> {% csrf_token %} <div class="form-group"> <label for="id_username">用户名</label> <input type="text" name="username" id="id_username" class="form-control" disabled value="{{ request.user.username }}"> </div> <div class="form-group"> <label for="id_old_password">旧密码</label> <input type="password" name="old_password" id="id_old_password" class="form-control"> </div> <div class="form-group"> <label for="id_new_password">新密码</label> <input type="password" name="new_password" id="id_new_password" class="form-control"> </div> <div class="form-group"> <label for="id_confirm_password">确认密码</label> <input type="password" name="confirm_password" id="id_confirm_password" class="form-control"> </div> <button class="btn btn-success" id="id_button">修改密码</button> <span class="errors" style="color: red" id="id_error"></span> </form> </div> </div> </div> </body> </html>
def set_password(request): old_password = request.POST.get('old_password') new_password = request.POST.get('new_password') confirm_password = request.POST.get('confirm_password') # 先判断旧密码是否正确 res = request.user.check_password(old_password) if res: # 再来比对新密码是否一致 if new_password == confirm_password: request.user.set_password(new_password) request.user.save() return redirect('/login/') return render(request,'set_password.html')