BBS项目搭建分步过程
1. 注册页面补充完善
# 注册前端文件 register.html文件中补充:
// 提交ajax
$.ajax({
url: '',
type: 'post',
data: myFormData,
contentType: false,
processData: false,
success: function (res) {
console.log(res)
if (res.status == 200) {
layer.msg(res.msg, {icon:1}, function () {
location.href = res.url;
})
} else {
layer.msg(res.msg,);
}
}
})
})
</script>
</body>
</html>
# views.py中补充:
from django.http import JsonResponse
from app01 import models
# 1.注册功能
def register(request):
# 后端一定要对参数进行验证
if request.method == 'POST':
# 返回的是json格式的数据
back_dic = {'status': 200, 'msg': '注册成功', 'data': {}}
# 1.1. 接收参数
username = request.POST.get('username')
password = request.POST.get('password')
re_password = request.POST.get('re_password')
email = request.POST.get('email')
img = request.POST.get('img')
# 1.2. 验证参数, 先验证不正确的参数
if not username:
'''
响应状态码
业务状态码
财务相关的业务,用户相关的,订单相关的
1001 2001 30
'''
back_dic['status'] = 1001
back_dic['msg'] = '用户名必须填写'
return JsonResponse(back_dic)
if password != re_password:
back_dic['status'] = 1002
back_dic['msg'] = '两次密码不一致'
return JsonResponse(back_dic)
# 验证用户名是否存在
res = models.UserInfo.objects.filter(username=username).first()
if res:
back_dic['status'] = 1003
back_dic['msg'] = '用户名已经存在'
return JsonResponse(back_dic)
# 1.3. 处理正确的业务逻辑
data_dic = {}
if img != 'undefined':
data_dic['avatar'] = img
# 处理密码
import hashlib
from django.conf import settings
m = hashlib.md5()
password = password + settings.SECRET_KEY
m.update(password.encode('utf8'))
password = m.hexdigest()
data_dic['username'] = username
data_dic['password'] = password
data_dic['email'] = email
# 1.4. 数据入库
models.UserInfo.objects.create(**data_dic) # 传入所有获取的数据
# 1.5. 返回数据
back_dic['url'] = '/login/'
return JsonResponse(back_dic)
return render(request, 'register.html')
2. 登录页面搭建
# views.py中写入登录以及验证码功能:
# 2. 登录
def login(request):
return render(request, 'login.html')
# 3. 生成验证码
"""
图片相关的模块
pip3 install pillow
"""
from PIL import Image, ImageDraw, ImageFont
"""
Image:生成图片
ImageDraw:能够在图片上乱涂乱画
ImageFont:控制字体样式
"""
from io import BytesIO, StringIO
"""
内存管理器模块
BytesIO:临时帮你存储数据 返回的时候数据是二进制
StringIO:临时帮你存储数据 返回的时候数据是字符串
"""
import random
def get_random():
# (100, 100, 100)
return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
def get_code(request):
# 写图片验证码
img_obj = Image.new('RGB', (430, 35), get_random())
img_draw = ImageDraw.Draw(img_obj) # 产生一个画笔对象
img_font = ImageFont.truetype('static/font/font.ttf', 30) # 字体样式 大小 字体文件可自行百度下载
# 随机验证码 五位数的随机验证码 数字 小写字母 大写字母
code = ''
for i in range(4):
random_upper = chr(random.randint(65, 90))
random_lower = chr(random.randint(97, 122))
random_int = str(random.randint(0, 9))
# 从上面三个里面随机选择一个
tmp = random.choice([random_lower, random_upper, random_int])
# 将产生的随机字符串写入到图片上
"""
为什么一个个写而不是生成好了之后再写
因为一个个写能够控制每个字体的间隙 而生成好之后再写的话
间隙就没法控制了
"""
img_draw.text((i * 60 + 60, -2), tmp, get_random(), img_font)
# 拼接随机字符串
code += tmp
print(code)
# 随机验证码在登陆的视图函数里面需要用到 要比对 所以要找地方存起来并且其他视图函数也能拿到
request.session['code'] = code
# request.session['code'] = code
io_obj = BytesIO()
img_obj.save(io_obj, 'png')
return HttpResponse(io_obj.getvalue())
# 新建login.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<h1 class="text-center">登录页面</h1>
<div class="col-md-8 col-md-offset-2">
<form action="">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" id="username" class="form-control">
</div>
<div class="form-group">
<label for="username">密码</label>
<input type="password" id="password" class="form-control">
</div>
<div class="form-group">
<label for="myfile">
验证码
</label>
<div class="row">
<div class="col-md-6">
<input type="text" class="form-control" id="get_code">
</div>
<div class="col-md-6">
<img src="/get_code/" id="re_code" alt="" style="width: 445px; height: 35px;">
</div>
</div>
</div>
<input type="button" class="btn btn-success btn-block" value="登录">
</form>
</div>
</div>
</div>
</body>
</html>
# 路由不要忘了:
# 登录页面
url(r'^login/', views.login),
# 生成验证码
url(r'^get_code/', views.get_code),
3. 登录后端逻辑的实现
import hashlib
from django.conf import settings
# 封装密码处理功能
def get_pwd(password):
m = hashlib.md5()
password = password + settings.SECRET_KEY
m.update(password.encode('utf-8'))
return m.hexdigest()
# 补充登录具体功能:
# 2. 登录
def login(request):
if request.method == 'POST':
# 定义返回数据的格式
back_dic = {'status': 200, 'msg': '登录成功', }
# 接收参数
username = request.POST.get('username')
password = request.POST.get('password')
code = request.POST.get('code')
# 验证参数
if code.upper() != request.session.get('code').upper(): # .upper() 转大写 不区分大小写了
back_dic['status'] = 1004
back_dic['msg'] = '验证码不正确'
return JsonResponse(back_dic)
if not username:
back_dic['status'] = 1005
back_dic['msg'] = '用户名必须填写'
return JsonResponse(back_dic)
# 登录逻辑
password = get_pwd(password) # 获取加密之后的密码
# res = models.UserInfo.objects.filter(username=username, password=password).first()
'''防止撞库 同时查询用户名和密码 不要只匹配一项就返回结果给用户'''
res = models.UserInfo.objects.filter(username=username, password=password).first()
if not res:
back_dic['status'] = 1006
back_dic['msg'] = '用户名或者密码不正确'
return JsonResponse(back_dic)
# 记录用户信息的
request.session['username'] = username
request.session['id'] = res.id
back_dic['url'] = '/home/'
return JsonResponse(back_dic)
return render(request, 'login.html')
# 在login.html中 添加数据提交:
"""
引入标签不要忘了:
<script src="/static/layer-v3.5.1/layer/layer.js"></script>
"""
"""body标签内添加script标签绑定事件:"""
<script>
// 更换验证码
$("#re_code").click(function () {
{#var old_code = $('#re_code').attr('src');#}
var old_code = $(this).attr('src');
{#$('#re_code').attr('src', old_code);#}
$(this).attr('src', old_code);
})
$('.btn').click(function () {
var username = $('#username').val();
var password = $('#password').val();
var code = $('#get_code').val();
// 验证参数
if (!username) {
layer.msg('用户名必须填写');
return
}
if (!password) {
layer.msg('密码必须填写');
return;
}
if (!code) {
layer.msg('验证码必须填写');
return;
}
var data = {'username': username, 'password': password, 'code': code}
// 提交ajax 请求
$.ajax({
url: '',
type: 'post',
data: data, // 参数过多时 单独定义变量存储
success: function (res) {
console.log(res); // 查看后端返回的数据,
if (res.status == 200) {
layer.msg(res.msg, {}, function () {
location.href = res.url;
})
} else {
layer.msg(res.msg)
}
}
})
})
</script>
4. 首页创建
# 路由:
# 首页
url(r'^home/', views.home),
# views.py补充首页功能:
# 4. 首页
def home(request):
return render(request, 'home.html', locals())
# 新建home.html文件 使用bootstrap的导航条样式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- 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="#">py20BBS</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 class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
<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>
<li role="separator" class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
{% if request.session.username %}
<li><a href="#">{{ request.session.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="#" data-toggle="modal" data-target=".bs-example-modal-lg">修改密码</a></li>
<li><a href="#">后台管理</a></li>
<li><a href="/logout/">退出系统</a></li>
</ul>
</li>
{% else %}
<li><a href="/register/">注册</a></li>
<li><a href="/login/">登录</a></li>
{% endif %}
</ul>
</div><!-- /.navbar-collapse -->
<div class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="row">
<h1 class="text-center">修改密码</h1>
<div class="col-md-8 col-md-offset-2">
<div class="form-group">
<label for="old_pwd">
原密码:
</label>
<input type="text" id="old_pwd" class="form-control">
</div>
<div class="form-group">
<label for="new_pwd">
新密码:
</label>
<input type="text" id="new_pwd" class="form-control">
</div>
<div class="form-group">
<label for="re_pwd">确认密码:</label>
<input type="text" id="re_pwd" class="form-control">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary set_pwd">提交</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div><!-- /.container-fluid -->
</nav>
</body>
</html>
5. 退出系统及修改密码功能的实现
# html文件内容在第4点 home.html文件中
# 添加路由:
# 退出系统
url(r'^logout/', views.logout),
# 修改密码
url(r'^set_pwd/', views.set_pwd),
# views.py补充功能:
# 5. 退出系统
def logout(request):
request.session.flush()
return redirect('/login/')
# 6. 修改密码
def set_pwd(request):
if request.method == 'POST':
# 返回的是json格式的数据
back_dic = {'status': 200, 'msg': '修改成功', 'data': {}}
# 1. 接收参数
old_pwd = request.POST.get('old_pwd')
new_pwd = request.POST.get('new_pwd')
re_pwd = request.POST.get('re_pwd')
# 验证参数
if not old_pwd:
back_dic['status'] = 1008
back_dic['msg'] = '原密码必须填写'
return JsonResponse(back_dic)
if re_pwd != new_pwd:
back_dic['status'] = 1009
back_dic['msg'] = '两次密码不一致'
return JsonResponse(back_dic)
# 修改密码
password = get_pwd(new_pwd) # 获取加密之后的密码
models.UserInfo.objects.filter(pk=request.session.get('id')).update(password=password)
return JsonResponse(back_dic)
# html文件内容写在第4点home.html文件中:
<script>
$('.set_pwd').click(function () {
var old_pwd = $('#old_pwd').val();
var new_pwd = $('#new_pwd').val();
var re_pwd = $('#re_pwd').val();
// 验证参数
if (!old_pwd) {
layer.msg('原密码必须填写');
return
}
if (!new_pwd) {
layer.msg('新密码必须填写');
return;
}
if (!re_pwd) {
layer.msg('确认必须填写');
return;
}
var data = {'old_pwd': old_pwd, 'new_pwd': new_pwd, 're_pwd': re_pwd}
// 提交ajax 请求
$.ajax({
url: '/set_pwd/',
type: 'post',
data: data,
success: function (res) {
console.log(res); // 查看后端返回的数据,
if (res.status == 200) {
layer.msg(res.msg, {}, function () {
location.reload();
})
} else {
layer.msg(res.msg)
}
}
})
})
</script>