BBS-注册功能
目录
重点功能:
- 上传图片
- 头像图片实时展示
- ajax方式提交给后端数据
一、添加路由
在路由urls.py中要先导入视图层和一些用到的模块
from django.conf.urls import url
from django.contrib import admin
from app01 import views
然后添加
# 注册的路由,用精准匹配
url(r'^register/$', views.register),
路由问题:如果没有参数尽量使用精准匹配,防止路由冲突
二、注册功能前端模板
前端步骤:
1.form表单展示数据框:用户名、密码、二次密码、邮箱、头像、button按钮
# button按钮,使用ajax提交数据,就不能使用submit了
2.头像图片格式
2.1 先设置默认头像,放到静态文件中,记得配置文件设置
2.2 img标签中加路径,并调整大小
<img src="/static/img/default.png" id="myimg" alt="" width="100px">
# 前端检查中可以先临时调整尺寸
2.3 点击图片就可以上传文件:把img标签放到label中,把file的input框隐藏掉
3.头像图片实时展示 # 用js
3.1 给myfile帮点change事件
3.2 自定义文件阅读器对象
3.3 获取新的图片真实数据
3.4 把文件数据交给文件阅读器
myFileReadObj.readAsDataURL(myfile);
3.5 给文件阅读器绑定onload事件
3.6 更改img标签的路径属性
$("#myimg").attr('src', myFileReadObj.result);
4.ajax方式提交给后端数据
4.1 获取前端form表单中输入的数据
4.2 参数的验证,参数不能为空、两次密码不一致
4.3 formdata对象,添加普通数据、文件数据、csrf验证
4.4 发起ajax请求:把前端输入的数据提交到后端
4.5 接收后端的返回信息,back_dic字典
# 记住:以后但凡遇到参数的时候,都需要验证!!!!!!!!
# 前端的验证是弱不禁风的,Django的后端一定要做验证,参数必填,参数不正确,参数不合法
'''作为一个后端开发人员,如果不验证参数,不是一个合格的后端开发人员'''
补充:前端检查图片的大小,只能用于临时调整
精细调整:点中自己改的尺寸,键盘上下键,就可以增删数据。优点:更方便
前端代码
layui网址:https://layui.gitee.io/v2/docs/modules/layer.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center">注册页面</h1>
<form action="">
<div class="form-group">
{# label标签的作用:当点击用户名时,也能够让输入框获取焦点 -->#}
{# label标签的 for 属性值应当与相关元素的 id 属性值相同。 -->#}
<label for="username">用户名:</label>
<input type="text" id="username" class="form-control">
</div>
<div class="form-group">
<label for="password">密码:</label>
<input type="password" id="password" class="form-control">
</div>
<div class="form-group">
<label for="re_password">确认密码:</label>
<input type="password" id="re_password" class="form-control">
</div>
<div class="form-group">
<label for="email">邮箱:</label>
<input type="text" id="email" class="form-control">
</div>
<div class="form-group">
<label for="myfile">上传头像:
<img src="/static/img/default.png" id="myimg" alt="" width="90px">
{# 图片路径写默认图片的静态路径,图片要调整大小 #}
</label> {# 点击图片就可以上传文件,就要把img标签放到label中 #}
<input type="file" id="myfile" style="display: none"> {# 隐藏file的input框 #}
</div>
{# 使用ajax提交给后端数据,所以type使用button #}
<input type="button" class="btn btn-primary btn-block commit" value="提交">
</form>
</div>
</div>
</div>
{# 引入layer文件 #}
<script src="/static/layer/layer.js"></script>
<script>
// 使用js来实时显示图片
$("#myfile").change(function () { {# 换张图片,文本域就会发生变化,所以绑定change事件 #}
// 1. 借助于文件阅读器
var myFileReadObj = new FileReader(); // 文件阅读器:可以读取文件
// 2. 获取新文件/图片数据
// var myfile = $("#myfile")[0].files[0];
var myfile = $(this)[0].files[0];
{# 事件函数中的this关键字,指代的就是当前被操作的标签对象本身 #}
// 3. 把你拿到的这个文件交给文件阅读器
myFileReadObj.readAsDataURL(myfile); // 这一步是异步提交
// 4.返回一个图片的数据
// 怎么显示新图片?就是把新图片的地址替换到默认图片的地址src=""中
myFileReadObj.onload = function () { {# 把图片读取完成后再执行更改属性操作:onload事件 #}
// 读出文件对象的图片地址
$("#myimg").attr('src', myFileReadObj.result);
{# 更改属性操作:attr、prop #}
}
});
// ajax方式提交给后端数据
$(".commit").click(function () {
// 1.获取前端form表单中输入的数据
var username = $("#username").val();
var password = $("#password").val();
var re_password = $("#re_password").val();
var email = $("#email").val();
var myfile = $("#myfile")[0].files[0];
// 2.参数的验证
if (!username) {
layer.msg('用户名必填!'); // 如果用户名没有填写,弹窗提示
return
{# 参数不正确直接退出 #}
}
if (!password) {
layer.msg('密码必须填写!')
return
}
if (!re_password) {
layer.msg('确认密码必须填写!')
return
}
if (!email) {
layer.msg('邮箱必须填写!')
return
}
// 其余参数你自己来验证,多个参数验证:方式1:可以写多个if条件。方式2:可以直接循环$.each()
// 两次密码不一致
if(password != re_password){
layer.msg('两次密码不一致');
return;
}
// 3.formdata对象
// 文件数据传输需要借助于formdata对象
var myFormDataObj = new FormData();
// 普通数据
myFormDataObj.append('username', username);
myFormDataObj.append('password', password);
myFormDataObj.append('re_password', re_password);
myFormDataObj.append('email', email);
// 文件数据
myFormDataObj.append('myfile', myfile);
//csrf_token验证
myFormDataObj.append('csrfmiddlewaretoken', '{{ csrf_token }}');
// 4.发起ajax请求:把前端输入的数据提交到后端
$.ajax({
url: '',
type: 'post',
data: myFormDataObj,
contentType: false, {# 使用myFormDataObj对象,需要加两个参数 #}
processData: false,
success: function (res) { // res=back_dic
if (res.code == 200) {
layer.msg(res.msg, {icon: 1}, function () {
location.href = res.url; // 跳转地址,前端BOM操作
});
} else { // 不成功的其余都只layer弹出各自的消息
layer.msg(res.msg);
}
}
})
})
</script>
</body>
</html>
前端重点操作
1、注册功能图片实时展示
步骤:
3.头像图片实时展示 # 用js
3.1 给myfile帮点change事件
3.2 自定义文件阅读器对象
3.3 获取新的图片真实数据
3.4 把文件数据交给文件阅读器
myFileReadObj.readAsDataURL(myfile);
3.5 给文件阅读器绑定onload事件
3.6 更改img标签的路径属性
$("#myimg").attr('src', myFileReadObj.result);
代码:
// 使用js来实时显示图片
{# 换张图片,文本域就会发生变化,所以绑定change事件 #}
$("#myfile").change(function () {
// 1. 借助于文件阅读器
var myFileReadObj = new FileReader(); // 文件阅读器:可以读取文件
// 2. 获取新文件/图片数据
{# var myfile = $("#myfile")[0].files[0]; #}
{# 事件函数中的this关键字,指代的就是当前被操作的标签对象本身 #}
var myfile = $(this)[0].files[0];
// 3. 把你拿到的这个文件交给文件阅读器
myFileReadObj.readAsDataURL(myfile); // 这一步是异步提交
// 4.返回一个图片的数据
{# 怎么显示新图片?就是把新图片的地址替换到默认图片的地址src=""中 #}
{# 把图片读取完成后再执行更改属性操作:onload事件 #}
myFileReadObj.onload = function () {
{# 更改属性操作:attr、prop #}
$("#myimg").attr('src', myFileReadObj.result); {# 读出文件对象的图片地址 #}
}
});
注意点:
- 前端的图片并没有上传成功,没有上传到后台
- base64的图片的真实数据,二进制形式
图片实时展示的第二种思路:
(可以自己写一下)
ajax提交文件数据,把图片上传到后台,django返回给前端一个json格式数据,内部带一个图片地址/路径,属性更改:
$("#myimg").attr('src', '后端传给前端的图片路径数据');
2、注册功能ajax提交数据
前端ajax方式提交给后端数据的逻辑步骤:
4.1 获取前端form表单中输入的数据
4.2 参数的验证,参数不能为空、两次密码不一致
4.3 formdata对象,添加普通数据、文件数据、csrf验证
4.4 发起ajax请求:把前端输入的数据提交到后端
4.5 接收后端的返回信息,back_dic字典
代码:
// ajax方式提交给后端数据
$(".commit").click(function () {
// 1.获取前端form表单中输入的数据
var username = $("#username").val();
var password = $("#password").val();
var re_password = $("#re_password").val();
var email = $("#email").val();
var myfile = $("#myfile")[0].files[0];
// 2.参数的验证
if (!username) {
layer.msg('用户名必填!'); // 如果用户名没有填写,弹窗提示
return
{# 参数不正确直接退出 #}
}
if (!password) {
layer.msg('密码必须填写!')
return
}
if (!re_password) {
layer.msg('确认密码必须填写!')
return
}
if (!email) {
layer.msg('邮箱必须填写!')
return
}
// 其余参数你自己来验证,多个参数验证:方式1:可以写多个if条件。方式2:可以直接循环$.each()
// 两次密码不一致
if(password != re_password){
layer.msg('两次密码不一致');
return;
}
// 3.formdata对象
// 文件数据传输需要借助于formdata对象
var myFormDataObj = new FormData();
// 普通数据
myFormDataObj.append('username', username);
myFormDataObj.append('password', password);
myFormDataObj.append('re_password', re_password);
myFormDataObj.append('email', email);
// 文件数据
myFormDataObj.append('myfile', myfile);
//csrf_token验证
myFormDataObj.append('csrfmiddlewaretoken', '{{ csrf_token }}');
// 4.发起ajax请求:把前端输入的数据提交到后端
$.ajax({
url: '',
type: 'post',
data: myFormDataObj,
contentType: false, {# 使用myFormDataObj对象,需要加两个参数 #}
processData: false,
success: function (res) { // res=back_dic
if (res.code == 200) {
layer.msg(res.msg, {icon: 1}, function () {
location.href = res.url; // 跳转地址,前端BOM操作
});
} else { // 不成功的其余都只layer弹出各自的消息
layer.msg(res.msg);
}
}
})
})
知识点:
location.href="URL" // 跳转到指定页面,前端BOM操作
BOM操作复习:https://www.cnblogs.com/zjyao/p/17335370.html#location对象务必掌握
拓展:
1.前端的参数验证:
如果有多个参数需要验证,可以使用$.each()方法,把每个输入框的id值拿到,并给每一个框加个msg属性(eg: msg="请输入用户名"),循环id,获取msg属性值。也可以直接简单的使用多个if判断条件即可
2.密码加密的问题
md5加密的位数是32位数,有的公司不会显示这么长,只显示16位,会先加密,然后切片截取,只显示16位。
三、添加视图函数
后端步骤
标准的后端逻辑:
1. 先定义返回给前端的数据格式
2. 接收参数
3. 验证参数!
4. 开始处理正常的业务逻辑
5. 返回前端数据:back_dic
注册功能中的业务逻辑:
4. 开始处理正常的业务逻辑 # 注册功能
4.1 密码加密
4.2 把数据添加到字典中,文件数据可传也可不传,需要判断
4.3 数据保存到数据库中
"""能在后端处理的就在后端处理"""
拓展:
业务状态码code:
是我们程序员自己写的,可以随意定义。
200:成功
一般是4为数字(eg:1001:用户名没有填写)
还可能出现6位(eg:421001,表示跟OA相关的(财务41 OA42 后台43 )),前两位表示业务模块,后4为表示响应状态码
还可能:0,代表成功。1,代表失败
后端代码
在views.py中,
1、导入要用到的模块
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse # ajax请求,后端返回json格式数据,引入JsonResponse
from django.conf import settings # 使用配置文件中的盐
from app01 import models # 入库操作,要导入model.py文件
import hashlib # 加密模块
2、加密函数
def get_md5_pwd(password):
"""加密函数"""
m = hashlib.md5()
s = password + settings.SECRET_KEY
m.update(s.encode('utf-8'))
return m.hexdigest()
3、然后添加视图函数 register
def register(request):
'''注册功能'''
# print(request.is_ajax()) # 判断是不是ajax提交
# ajax的请求方式有get,post,不适合现在使用
if request.method == 'POST':
'''由于现在我们用的是ajax发起的请求,所以,我们后端一般返回json格式的数据,轻量级数据格式,速度快,优点多'''
# 1. 先定义返回给前端的数据格式
# code:叫业务状态码 200 1001 1002 1003----------> 财务411001 oa4210001 后台431001 订单 4410001
# back_dic = {'code': 200, 'msg': '注册成功', 'data': []} # 标准的返回给前端的数据格式
back_dic = {'code': 200, 'msg': '注册成功'}
# 2. 接收参数
username = request.POST.get('username')
password = request.POST.get('password')
re_password = request.POST.get('re_password')
email = request.POST.get('email')
myfile = request.FILES.get('myfile') # 文件数据用FILES接收
# 3. 验证参数!!!!!!!, 作为后端开发人员,必须验证参数,验证的是合法的参数
# 验证参数的时候,一定先验证错误的参数,不合法的参数,按照反向逻辑写
if not username:
back_dic['code'] = 1001
back_dic['msg'] = '用户名必须填写'
return JsonResponse(back_dic)
if not password:
back_dic['code'] = 1002
back_dic['msg'] = '密码必须填写'
return JsonResponse(back_dic)
if not re_password:
back_dic['code'] = 1003
back_dic['msg'] = '确认密码必须填写'
return JsonResponse(back_dic)
if not email:
back_dic['code'] = 1004
back_dic['msg'] = '邮箱必须填写'
return JsonResponse(back_dic)
# 验证两次密码不一致
if password != re_password:
back_dic['code'] = 1005
back_dic['msg'] = '两次密码不一致'
return JsonResponse(back_dic)
# 4. 开始处理正常的业务逻辑
'''你完全可以使用auth模块,但是这里我不给你用auth模块,因为太简单了,扩展性不好。可以自己尝试一下使用auth模块'''
# 4.1 密码加密
new_pwd = get_md5_pwd(password)
# 4.2 把数据添加到字典中
data_dic = {} # 字段比较多的时候,直接创建关键字传参的字典
data_dic['username'] = username
data_dic['password'] = new_pwd
data_dic['email'] = email
# 文件数据可传也可不传
if myfile:
data_dic['avatar'] = myfile # 保存的是图片路径到avatar中
# 4.3 数据保存到数据库中
# models.UserInfo.objects.create(username=username, password=new_pwd, email=email, avatar=myfile)
models.UserInfo.objects.create(**data_dic)
# 5. 返回前端数据
back_dic['url'] = '/login/' # 注册成功后跳转到登录页面
return JsonResponse(back_dic)
return render(request, 'register.html')