BBS登录注册技术点归纳
注册功能
方案技术点
-
使用form组件来校验表单的输入值是否合法;
-
前端使用ajax来提交用户上传的数据;
-
动态显示用户上传的头像:
(1)通过
label
的for
属性来关联file-input框的id
,当用户点击label
的时候,其实在点击file-input框
(2)借助文件阅读器对象
fileReader
将图片动态显示
上传头像部分代码
//上传头像
<label for="id_avatar">
<img src="{% static 'img/default.png' %}" id="img" alt="" title="点击上传头像"
style="width: 80px;height: 80px;border-radius: 50%">
</label>
<input type="file" name="avatar" id="id_avatar" style="display: none"> //通过display来隐藏input框
//给input框来绑定一个文本域改变事件
$('#id_avatar').change(function () {
//生成一个文件阅读器对象
let myFileReaderObj = new FileReader();
//获取用户上传的文件对象
let fileObj = $(this)[0].files[0];
//将文件对象交给文件阅读器对象读取
myFileReaderObj.readAsDataURL(fileObj); //异步操作,IO操作
//利用文件阅读器,将文件展示到前端,即修改src属性
//等待文件阅读器加载完毕后再执行
myFileReaderObj.onload = function () {
$('#img').attr('src', myFileReaderObj.result)
}
});
- 使用
FormData对象
来存储用户上传的数据,包括文件:- 通过Form组件的
auto_id
属性来获取添加Form组件渲染标签的id
值,一般都是id_字段名
; - 通过
serializeArray()
方法序列化表单值来创建对象数组(名称和值); - 通过
each()
方法来对数组进行遍历;
- 通过Form组件的
<form id="regForm">
{% csrf_token %}
{% for form in register_form %}
<label for="{{ form.auto_id }}">{{ form.label }}</label>
{{ form }}
<span class="pull-right" style="color: red"></span>
{% endfor %}
</form>
<div class="modal-footer">
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary btn-sm" id="id_register">注册</button>
</div>
//注册功能
$('#id_register').on('click', function () {
//发送ajax请求,发送的数据既包括普通键值对,也包括文件
let formDataObj = new FormData();
// serializeArray() 方法通过序列化表单值来创建对象数组(名称和值)
{#console.log($('#my_form').serializeArray()) [{}, {}, {}, {}, {}, {}, {}]#}
$.each($('#regForm').serializeArray(), function (index, obj) {
//$.each()是对数组,json和dom结构等的遍历
//添加普通的键值对
formDataObj.append(obj.name, obj.value);
//添加文本数据
formDataObj.append('avatar', $('#id_avatar')[0].files[0]);
});
//获取 input框选中值的3种方式
{#$('input:radio:checked').val();#}
{#$("input[type='radio']:checked").val();#}
{#$("input[name='gender']:checked").val();#}
formDataObj.append('gender', $("input[type='radio']:checked").val());
formDataObj.append('csrfmiddlewaretoken', '{{ csrf_token }}');
//发送ajax请求
$.ajax({
url: '/register/',
type: 'post',
data: formDataObj,
//ajax上传文件需要指定两个关键性的参数
contentType: false,
processData: false,
success: function (args) {
//异步回调函数
if (args.code === 1000) {
$('#regModal').modal('hide');
swal({
title: 'register success',
type: 'success',
confirmButtonText: 'ok',
closeOnConfirm: false,
},
function () {
window.location.href = '/home/'
}
);
} else {
//通过Dom操作将错误的提示信息展示到input框下面
$.each(args.msg, function (field, erros) {
$(`#id_${field}`).next().text(erros[0]).parent().addClass('has-error')
})
}
}
})
});
- 通过Dom操作将后端返回的提示信息展示到前端页面:
- 后端通过JsonResponse对象给前端返回一个字典对象,如
back_dict={'code':1000,'msg':''}
; - 借助模板字符串手动拼接
id
,使用jQuery的Dom操作来渲染错误提示信息标签; - 使用JQuery的链式操作来清空错误提示信息标签的文本,去除
has-error
属性
- 后端通过JsonResponse对象给前端返回一个字典对象,如
def register(request):
"""用户注册函数"""
if request.method == 'POST':
back_dict = {'code': 1000, 'msg': ''}
# 检验数据是否合法
form_obj = RegForm(request.POST)
# 注意只有执行form_obj.is_valid(),才可能有form_obj.cleaned_data,form_obj.errors
if not form_obj.is_valid():
back_dict['code'] = 1001
back_dict['msg'] = form_obj.errors
else:
clean_data = form_obj.cleaned_data
clean_data.pop('confirm_password')
"""针对用户头像一定要判断是否传值 不能直接添加到字典里面去"""
if request.FILES.get('avatar'):
add_info['avatar'] = request.FILES.get('avatar')
models.UserInfo.objects.create_user(**clean_data)
return JsonResponse(back_dict)
////通过Dom操作将错误的提示信息展示到input框下面
$.each(args.msg, function (field, erros) {
$(`#id_${field}`).next().text(erros[0]).parent().addClass('has-error')
})
//给所有的input框绑定绑定获取焦点事件
$('input').on('focus', function () {
$(this).next().text('').parent().removeClass('has-error');
$('#error_msg').text('');
$('.changePwdError').text('');
});
登录功能
- 借助
random模块
和PIL模块
来产生随机验证码; - 通过request.session来存储验证码
code
; - 借助内存管理器来实现临时存储文件数据;
- 通过get请求自动刷新验证码
后端生成随机验证码部分代码
def get_random():
"""随机返回RGB三元组"""
return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
def make_code():
index = 0
code = ''
for i in range(code_settings.RANDOM_NUMBER):
random_list = []
for item in code_settings.CODE_LIST:
...
code += random.choice(random_list)
img_obj = Image.new('RGB', [200, 35], get_random()) # 生成图片(设置大小,颜色)
img_draw = ImageDraw.Draw(img_obj) # 产生一个画笔对象
img_font = ImageFont.truetype('static/font/style1.ttf', 30) # 设置 code的字体样式
for item in code:
img_draw.text((index * 30 + 30, 2), item, get_random(), img_font)
index += 1
io_obj = BytesIO() # 生成一个内存管理器对象
img_obj.save(io_obj, 'png') # 将文件以'png'的格式临时存储到内存管理器中
return code, io_obj # 返回code 以及图片的二进制数据
"""
from PIL import Image, ImageDraw, ImageFont
Image:生成图片
ImageDraw:能够在图片上乱涂乱画
ImageFont:控制字体样式
from io import BytesIO, StringIO
内存管理器模块
BytesIO:临时帮你存储数据 返回的时候数据是二进制
StringIO:临时帮你存储数据 返回的时候数据是字符串
"""
- 自动刷新验证码(每点击一次图片相当于在原来的url后面加了个?)
//动态刷新二维码
$('#code_img').on('click', function () {
let current_url = $(this).attr('src');
$(this).attr('src', `${current_url}?`)
});
注册功能演示
通过模态框来实现注册功能的弹框