BBS登录注册技术点总结
注册功能技术点
- 使用forms组件的表单校验功能,前端通过ajax将表单内用户注册信息提交到后端视图层。
- 在前端页面上实现用户点击默认头像,弹出文件选择框,并在用户选择图片后将图片自动显示在页面上。
- 将file类型的input输入框通过
style="display: none"隐藏起来; - 将显示图片的img标签放在label标签(for属性关联file的id)中,此时点击图片则自动弹出文件选择框;
- 通过js代码实现用户选择的图片自动展示到默认图片位置上。此时借助js的文件阅读器对象
FileReader
- 将file类型的input输入框通过
<div class="form-group">
<label for="id_avatar">头像
<img src="{% static 'img/default.png' %}" alt="" id="img_avatar" width="100" style="margin-left: 10px">
<input type="file" id="id_avatar" name="avatar" style="display: none">
</label>
</div>
<script>
{# 选择图片立刻显示,文本域改变事件change, 文件阅读器对象FileReader #}
$('#id_avatar').change(function () {
let myFileReaderObj = new FileReader(); // 1 先生成一个文件阅读器对象
let fileObj = $(this)[0].files[0]; // 2 获取用户上传的头像文件
myFileReaderObj.readAsDataURL(fileObj); // 3 将文件对象交给阅读器对象读取, 异步操作,需要等待加载结束后再显示图片
myFileReaderObj.onload = function () {
$('#img_avatar').attr('src', myFileReaderObj.result)
}
});
</script>
- 通过ajax请求将表单数据传给后端,如果数据较多,此时可以通过循环将多个数据循环添加到
FormData对象中- 技巧:使用form标签仅仅是将input标签包起来,而不是用form标签提交数据
$('#myform').serializeArray()这样操作可以获得一个数组,数组每个元素是一个自定义对象(字段名:字段值)
<form id="myform">
...标签渲染部分忽略...
<input type="button" id="reg_btn" class="btn btn-primary pull-right" value="注册">
</form>
<script>
{# ajax请求 #}
$('#reg_btn').click(function () {
let formDataObj = new FormData();
$.each($('#myform').serializeArray(), function (index, obj) {
formDataObj.append(obj.name, obj.value); // 将字段名和字段值一次加入formDataObj
});
formDataObj.append('avatar', $('#id_avatar')[0].files[0]); // 加入文件对象
$.ajax({
url:'{% url "register" %}',
type: 'post',
data: formDataObj,
contentType: false,
processData: false,
success: function (args) {
alert(args);
}
})
});
</script>
- 此时通过ajax提交数据时,后端forms表单校验失败,错误信息如何返回并展示到前端页面
- forms组件渲染标签时,前端页面每个输入框的id值都是
id_字段名的形式 - 而前端ajax收到的响应结果是一个对象,键是字段,值是错误信息列表
- 这样就可以手动拼接id,并借助jquery的DOM操作找到预留提示信息的位置。
- 并且通过jquery的链式操作可以方便的设置文本框的错误提示颜色和输入框聚焦时移除提示信息和输入框颜色
- forms组件渲染标签时,前端页面每个输入框的id值都是
# 后端
def post(self, request):
back_info = {'code': 1000}
form_obj = myforms.RegForm(request.POST)
if form_obj.is_valid():
pass
else:
back_info['code'] = 2000
back_info['msg'] = form_obj.errors # 将所有错误信息全部返回给前端
return JsonResponse(back_info)
# 前端
{% for form in form_obj %}
<div class="form-group">
<label for="{{ form.auto_id }}">{{ form.label }}</label>
{{ form }}
<span style="color: red" class="pull-right">{{ form.errors.0 }}</span>
</div>
{% endfor %}
<script>
$.ajax({
url:'{% url "register" %}',
type: 'post',
data: formDataObj,
contentType: false,
processData: false,
success: function (args) {
if (args.code === 1000){
window.location.href = args.url; // 成功时,跳转登录页面
}else{ // 失败时,手动拼接id值,DOM找到展示位置
$.each(args.msg, function (field, errors) {
$(`#id_${field}`).next().text(errors[0]).parent().addClass('has-error');
})
}
}
{# 聚焦输入框,提示信息消失 #}
// 给所有的input框绑定获取焦点事件
$('input').click(function () {
$(this).next().text('').parent().removeClass('has-error');
})
</script>
登录功能技术点
-
前端用一个图片img标签展示验证码图片,通过
img标签的src属性获取后端发送的验证码图片二进制数据 -
使用
pillow模块生成随机图片验证码(随机数字字母)。 -
使用
io内存管理器模块,临时帮你存储数据。 -
验证码保存在session中,用于登录校验。
<div class="col-md-6">
<img src="{% url 'get_code' %}" alt="" id="code_img" width="380" height="35">
</div>
后端生成验证码图片的视图函数
import string, random
def get_code(request):
def get_random():
# 返回一个随机三元祖,如(23, 34, 45)用于rgb三基色设置
return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
img_obj = Image.new('RGB', (380, 35), get_random()) # 图片格式、大小、颜色
img_draw = ImageDraw.Draw(img_obj) # 产生一个画笔对象
img_font = ImageFont.truetype('static/font/font.ttf', 30) # 字体样式 大小
digits_letters = string.digits + string.ascii_letters # string模块快速获取数字+大小写字母
code = ''.join(random.choices(digits_letters, k=5)) # random 随即取5个字符
for i in range(5):
tmp = code[i]
img_draw.text((i*60+60, -2), tmp, get_random(), img_font)
request.session['code'] = code.lower() # 保存在session中,且忽略大小写
io_obj = BytesIO()
img_obj.save(io_obj, 'png')
return HttpResponse(io_obj.getvalue()) # 给前端img的src属性返回该图片的二进制数据
- 实现点击验证码图片刷新验证码,这样设置后,每次点击图片相当于朝后端发一次get请求获取一张新的验证码图片
{# 点击验证码图片刷新验证码 #}
$('#code_img').click(function () {
$(this).attr('src', '{% url "get_code" %}?') // src='/get_code/?'url后面加?的操作
});
补充1:模块功能
图片相关的模块 pip3 install pillow
from PIL import Image,ImageDraw,ImageFont
"""
Image:生成图片
ImageDraw:能够在图片上乱涂乱画
ImageFont:控制字体样式
"""
内存管理器模块,避免IO频繁操作降低效率
from io import BytesIO,StringIO
"""
BytesIO:临时帮你存储数据 返回的时候数据是二进制
StringIO:临时帮你存储数据 返回的时候数据是字符串
"""
补充2:验证码生成方法推导演化
# 推导步骤1:直接获取后端现成的图片二进制数据发送给前端
with open(r'static/img/111.jpg','rb') as f:
data = f.read()
return HttpResponse(data)
# 推导步骤2:利用pillow模块动态产生图片
img_obj = Image.new('RGB',(430,35),'green')
img_obj = Image.new('RGB',(430,35),get_random())
# 先将图片对象保存起来
with open('xxx.png','wb') as f:
img_obj.save(f,'png')
# 再将图片对象读取出来
with open('xxx.png','rb') as f:
data = f.read()
return HttpResponse(data)
# 推导步骤3:文件存储繁琐IO操作效率低 借助于内存管理器模块
img_obj = Image.new('RGB', (430, 35), get_random())
io_obj = BytesIO() # 生成一个内存管理器对象 你可以看成是文件句柄
img_obj.save(io_obj,'png')
return HttpResponse(io_obj.getvalue()) # 从内存管理器中读取二进制的图片数据返回给前端
# 最终步骤4:写图片验证码
img_obj = Image.new('RGB', (430, 35), get_random())
img_draw = ImageDraw.Draw(img_obj) # 产生一个画笔对象
img_font = ImageFont.truetype('static/font/222.ttf',30) # 字体样式 大小

浙公网安备 33010602011771号