BBS项目-登录功能
1 登录页面搭建
登录页面,需要输入用户名、密码、验证码,这里不用form标签,我们自己手写3个input标签。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% load static %}
<script src="{% static 'jQuery-3.6.0.js' %}"></script>
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
<title>Title</title>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center">登录</h1>
<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_pwd">密码</label>
<input type="password" name="password" id="id_pwd" class="form-control">
</div>
<div class="form-group">
<label for="">验证码</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="{% static 'img/default.png' %}" alt="" width="420px" height="35px">
</div>
</div>
</div>
<input type="button" class="btn btn-success" value="登录">
</div>
</div>
</div>
</body>
</html>
先用默认图片占位,页面展示效果如下:
2 图片验证码
我们要做图片验证码,即图片和验证码都是动态展示的。
img标签的src属性的三种方式:1、图片文件路径 2、url 3、图片的二进制数据。
图片文件路径是固定的,我们想要动态展示,需要把src属性设置为url(路由),每当访问登录页面时,朝该url发送get请求,由后端接口动态返回二进制数据展示,login.html
<div class="col-md-6">
<img src="/get_code/" alt="" width="430px" height="35px">
</div>
views.py
推导步骤1:直接获取后端现成的图片二进制数据发送给前端
def get_code(request):
with open(r'static/img/222.jpg', 'rb') as f:
data = f.read()
return HttpResponse(data)
后端get_code接口返回图片的二进制数据,显然读取文件的方式存在问题,因为每次访问,验证码图片都是动态变化的,本地文件是有限的。
2.1 图片相关模块
只要涉及到操作图片,一般都会用到pillow模块。
pip3 install pillow
from PIL import Image, ImageDraw, ImageFont
# Image:生成图片对象
# ImageDraw:生成画笔对象,能够在图片上乱涂乱画
# ImageFont:生成字体对象,控制字体样式
推导步骤2:利用Image生成图片,第一个参数固定模式、第二个参数是前端设置的图片长宽、第三个参数是颜色,颜色可以放入三色参数(123,23,23),利用random模块随机放入三色参数,实现图片颜色动态变化。
from PIL import Image, ImageDraw, ImageFont
import random
def get_color():
# 返回多个数据,如果没有指定类型,默认按元组形式组织数据
return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
def get_code(request):
# img_obj = Image.new('RGB', (430, 35), 'red')
# img_obj = Image.new('RGB', (430, 35), (25, 25, 25))
img_obj = Image.new('RGB', (430, 35), get_color())
with open('xxx.png', 'wb') as f: # 生成的图片先保存在本地,save方法写数据(文件句柄,图片格式)
img_obj.save(f, 'png')
with open('xxx.png', 'rb') as f: # 再读取图片二进制数据,返回到前端
data = f.read()
return HttpResponse(data)
文件存储繁琐,IO操作频繁,效率低,需要借助于内存管理器模块。
2.2 内存管理器模块
推导步骤3:利用文件管理器对象帮我们临时存取数据。
from io import BytesIO, StringIO
# BytesIO:临时帮你存储数据 返回的时候数据是二进制
# StringIO:临时帮你存储数据 返回的时候数据是字符串
def get_code(request):
img_obj = Image.new('RGB', (430, 35), get_color())
io_obj = BytesIO() # 生成一个内存管理器对象,可以看成是文件句柄
img_obj.save(io_obj, 'png') # 类似于img_obj.save(f, 'png'), 第二个参数是图片类型
return HttpResponse(io_obj.getvalue()) # 直接从内存管理器中读取二进制的图片数据,返回给前端
2.3 最终步骤
通过前3步推导实现了图片的动态展示,我们还需要在图片上动态显示验证码,即要在图片上写字。
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO, StringIO
import random
def get_code(request):
img_obj = Image.new('RGB', (430, 35), get_color()) # 生成图片对象
img_draw = ImageDraw.Draw(img_obj) # 生成画笔对象
img_font = ImageFont.truetype('static/font/222.ttf', 30) # 生成字体对象,第一个参数是字体样式,第二个参数是字体大小
# 随机验证码:5位数的随机验证码,包含数字、大小写字母
code = ''
for i in range(5):
random_upper = chr(random.randint(65, 90)) # 随机大写字母
random_lower = chr(random.randint(97, 122)) # 随机小写字母
random_inter = str(random.randint(0, 9)) # 0-9随机数字,要转成字符串形式
tmp = random.choice([random_upper, random_lower, random_inter]) # 每循环一次,从上面三个元素中随机选择一个
"""
将产生的随机字符串写在图片上,为什么一个个写而不是5个生成好了之后再写?因为一个个写能够控制每个字体的间隙
第一个参数是字在图片上的坐标xy,x轴控制字的间隙,每循环一次,随i而等距离变化,y轴固定不变
第二个参数是循环出来的字符,第三个参数是图片颜色,第四个参数是字体样式
"""
img_draw.text((i*60+60, 0), tmp, get_color(), img_font)
code += tmp # 拼接随机字符串,for循环完后,就获取到5位数随机验证码code
request.session['code'] = code # 随机验证码要提交给登录的视图函数后端进行比对,所以要找地方存起来,并且其他视图函数也能拿到
io_obj = BytesIO() # 利用内存管理器帮你存储数据并返回给前端
img_obj.save(io_obj, 'png')
return HttpResponse(io_obj.getvalue())
登录页面效果如下:
2.4 局部刷新验证码图片
如果验证码看不清需要更换,但是点击刷新网页是整体刷新,我们要实现局部刷新,即点击验证码图片换一张,但整体页面不刷新。
我们打开浏览器调试,找到img标签,src属性是获取验证码的url,在这个url后随便加一个东西,url变了,它会朝新的url发get请求,图片就会自动刷新。
因此,我们给img标签绑定一个点击事件,每次点击,给src属性后加一个?
<div class="col-md-6">
<img src="/get_code/" alt="" width="450px" height="35px" id="id_img">
<span class="pull-right">图片看不清,点击换一张</span>
</div>
<script>
$('#id_img').click(function (){
let oldVal = $(this).attr('src'); // 拿到之前src的url,再给它重新赋值,用字符串拼接
$(this).attr('src', oldVal += '?'); // 每点击图片,就会给img标签src的url后面加一个?
})
</script>
3 ajax提交post请求
在登录标签下加一个span标签,所有的错误信息在span标签展示。
<input type="button" class="btn btn-success" value="登录" id="id_button">
<span style="color: red" id="id_error"></span>
给button按钮绑定点击事件,提交post请求。 csrf校验用的js配置,因此不需要在data中传入 'csrfmiddlewaretoken':'{{ csrf_token }}'
$('#id_button').click(function (){
$.ajax({
url: '',
type: 'POST',
data: {
'username': $('#id_username').val(),
'password': $('#id_pwd').val(),
'code': $('#id_code').val()
},
success: function(args){
if (args.code === 0){
window.location.href = args.url
}else {
$('#id_error').text(args.msg)
}
}
})
})
4 后端登录接口
views.py
def login(request):
if request.method == 'POST':
back_dic = {'code': 0, 'msg': ''}
username = request.POST.get('username')
password = request.POST.get('password')
code = request.POST.get('code')
# 校验验证码 忽略大小写
if code.upper() == request.session.get('code').upper():
# 用auth组件校验用户名与密码
user_obj = auth.authenticate(request, username=username, password=password)
if user_obj:
auth.login(request, user_obj)
back_dic['url'] = '/home/'
else:
back_dic['code'] = 1
back_dic['msg'] = '用户名或密码错误'
else:
back_dic['code'] = 1
back_dic['msg'] = '验证码错误'
return JsonResponse(back_dic)
return render(request, 'login.html')
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人