【bbs02补】注册功能form组件-前端-后端-总结、登录功能(前端、后端、生成验证码)

server/2024/10/21 9:48:18/

1 注册功能
1.1 注册功能form组件
1.2 注册功能前端
1.3 注册功能后端
1.4 forms组件和前后端总结
2 登录功能
2.1 登录前端
2.2 生成验证码

1 注册功能

1.1 注册功能form组件

# 注册页面-用户名-密码-确认密码-邮箱-手机号-头像# form组件 可以帮助我们1 快速生成前端页面2 数据校验3 错误处理# 如何使用-1 写一个类,继承forms.Form-2 在类中写属性和方法-属性:要跟咱们要校验或自动生成页面的字段一一对应-方法:对字段进行校验:clean_字段名 给单个字段校验clean 给多个字段校验-3 在视图函数中使用-4 模板中使用#  form表单中,如果定义了button或input 类型是"submit",只要点击,就会默认触发form表单的提交,如果我们又写了ajax提交,就会触发两次---》导致问题--把它搞外面-input 类型是"button"
from django import forms
from django.forms import widgets, ValidationError
from .models import UserInfoclass RegisterForm(forms.Form):# max_length=18 最长 18# min_length=3 最短 3# required=True 必填username = forms.CharField(max_length=18, min_length=3, required=True,label='用户名',error_messages={'required': '用户名字段必填','max_length': '长度不能超过18','min_length': '最短3'}, widget=widgets.TextInput(attrs={'class': 'form-control'}))password = forms.CharField(max_length=18, min_length=3, required=True,label='密码',error_messages={'required': '用户名字段必填','max_length': '长度不能超过18','min_length': '最短3'}, widget=widgets.PasswordInput(attrs={'class': 'form-control'}))re_password = forms.CharField(max_length=18, min_length=3, required=True,label='确认密码',error_messages={'required': '用户名字段必填','max_length': '长度不能超过18','min_length': '最短3'}, widget=widgets.PasswordInput(attrs={'class': 'form-control'}))email = forms.EmailField(max_length=18, min_length=3, required=True,label='邮箱',error_messages={'required': '用户名字段必填','max_length': '长度不能超过18','min_length': '最短3'}, widget=widgets.EmailInput(attrs={'class': 'form-control'}))phone = forms.CharField(max_length=11, min_length=11, required=True,label='手机号',error_messages={'required': '用户名字段必填','max_length': '长度不能超过11','min_length': '必须11为'}, widget=widgets.TextInput(attrs={'class': 'form-control'}))# 方法名只能写两类# 一类是  clean_字段名  校验单个字段def clean_username(self):  # 如果能走到这里,说明上面的校验已经通过了,校验过后的数据都放在一个字典中---》cleaned_datausername = self.cleaned_data.get('username')# 用户名不能以sb开头if username.startswith('sb'):# 校验不通过,抛异常raise ValidationError('名字不能以sb开头')# 如果用户名存在,也不能注册了res = UserInfo.objects.filter(username=username).exists()if res:raise ValidationError('该用户已经存在')return username# 二类是  clean   同时校验多个字段def clean(self):password = self.cleaned_data.get('password')re_password = self.cleaned_data.get('re_password')if not password == re_password:raise ValidationError('两次密码不一致')return self.cleaned_data

1.2 注册功能前端

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="/static/js/jquery.min.js"></script><link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
</head>
<body><div class="container-fluid"><div class="row"><div class="col-md-6 col-md-offset-3"><h1 class="text-center">注册功能</h1><form id="register_form">{% csrf_token %}{% for foo in form %}<div class="form-group"><label for="{{ foo.auto_id }}">{{ foo.label }}</label>{{ foo }} <span class="pull-right error" style="color: red"></span></div>{% endfor %}<div class="form-group"><label for="id_avatar">头像<img src="/static/img/default.png" alt="" height="80px" width="80px" id="id_img"style="margin-left: 20px"></label><input type="file" id="id_avatar" class="form-control" accept="image/*" style="display: none"></div><div class="text-center"><input type="button" value="注册" class="btn btn-danger" id="id_submit"><span class="error" style="color: darkred;margin-left: 10px" id="id_error"></span></div></form></div></div>
</div></body><script>// 1 监控文件变化$('#id_avatar').change(function () {// 读出input 的图片,写到 img标签上// 需要借助于文件阅读器var fileReader = new FileReader();// 把文件对象读入文件阅读器中fileReader.readAsDataURL($('#id_avatar')[0].files[0])// 等文件读完,再放入fileReader.onload = function () {//$('#id_img').attr('height', '300px')$('#id_img').attr('src', fileReader.result)//$('#id_img')[0].src = fileReader.result}})// 2 按钮提交---》注册功能$('#id_submit').click(function () {var formdata = new FormData()// 把文件放入formdata.append('my_img', $('#id_avatar')[0].files[0])//放数据:用户名,密码,确认密码,手机号,邮箱 ,你可以一个个放--->笨办法/*formdata.append('username', $('#id_username').val())formdata.append('password', $('#id_password').val())formdata.append('re_password', $('#id_re_password').val())formdata.append('phone', $('#id_phone').val())formdata.append('email', $('#id_email').val())formdata.append('csrfmiddlewaretoken', '{{ csrf_token }}') // csrf 的token*/// 简单方案var register_form = $('#register_form').serializeArray() // 会把当前form表单中得数据放到列表套字典的形式/*数组[{name:xx,value:yy}, {…}, {…}, {…}, {…}]*///console.log(register_form)// jq 的循环$.each(register_form, function (i, v) {//console.log(v['name'])//console.log(v['value'])formdata.append(v['name'], v['value'])})$.ajax({url: '/register/',method: 'post',processData: false,contentType: false,data: formdata,success: function (data) {if (data.code == 100) {location.href = '/login/'} else { // 不成功// 两次密码不一致,把错误写在 注册按钮后面// input 自己的错误,写在自己后面// 循环返回的错误$.each(data.errors, function (key, value) {if (key == '__all__') {$('#id_error').html(value[0])}$('#id_' + key).next().html(value[0]).parent().addClass('has-error')})// 过3s后,清空错误,和红框setTimeout(function () {$('.error').html("").parent().removeClass('has-error')//alert('asfdsdaf')}, 3000)}}})})// 3 当用户名输入框失去焦点,我们就去后端校验用户名是否注册过$('#id_username').blur(function () {//alert('失去焦点了')//var username=$('#id_username').val()var username = $(this).val()$.ajax({url: '/check_username/?username=' + username,method: 'get',success: function (data) {console.log(data)if (data.code != 100) {// 1 清空输入框//$(this).val()// 2 错误提示//$(this).next().html(data.msg)console.log('ssss')// 两句可以并做一句---》链式调用// 如果在另一个内部函数中,就不能用this//var ss=$('#id_username').val()//$('#id_username').next().html(data.msg).parent().addClass('has-error').children('input').val("")$('#id_username').val('').next().html(data.msg).parent().addClass('has-error')}}})})</script>
</html>

1.3 注册功能后端

from django.shortcuts import render
from .forms import RegisterForm
from .models import UserInfo
from django.http import JsonResponsedef register(request):if request.method == 'GET':form = RegisterForm()return render(request, 'register.html', {'form': form})else:# # 1 数据# print(request.POST)# # 2 文件# print(request.FILES.get('my_img'))# 取出头像avatar = request.FILES.get('my_img')# 校验数据是否合法'''username: adminpassword: 123email: an@qq.comphone: 12345678935avatar:文件'''form = RegisterForm(request.POST)  # 使用form校验传入的数据if form.is_valid():  # 校验通过# 保存data = form.cleaned_data# 把re_password 弹出data.pop('re_password')# 把头像加入if avatar:data['avatar'] = avatarUserInfo.objects.create_user(**data)return JsonResponse({'code': 100, 'msg': '注册成功'})else:return JsonResponse({'code': 101, 'msg': '注册失败', 'errors': form.errors})# 校验用户名是否存在的接口
def check_username(request):username = request.GET.get('username')res = UserInfo.objects.filter(username=username).exists()if res:# 约定状态码:100,表示成功,非100表示失败return JsonResponse({'code': 101, 'msg': '用户已经存在'})return JsonResponse({'code': 100, 'msg': '您可以注册'})

1.4 forms组件和前后端总结

# 1 forms组件-1 渲染模板-2 校验数据-3 渲染错误- form=RegisterForm()---渲染页面- form=RegisterForm(requets.POST)---校验数据
# 2 取数据,取文件-form-data提交数据-request.POST             中取数据-request.FILES.get('名字') 取文件-补:前端是key:value    后端变成了  key:[value]-request.data 不是真正的字典{'username': ['admin','xxx'], 'password': ['123']}request.POST.get('username')request.POST.getlist('username')# 3 保存 文件和数据# data 是form校验过后的数据,没有头像data.pop('re_password') # 不是表的字段# 把头像加入 头像是表的字段if avatar:data['avatar'] = avatar # 文件对象# avatar = models.ImageField(upload_to='avatar', default='avatar/default.png')内部自动:打开一个空文件,把文件写入到空文件中 【/media/avatar/,并且把路径赋值给avatar数据库字段UserInfo.objects.create_user(**data)# 4 前端:头像实时显示-隐藏了 input  file---input只能接收图片类型-只要input发生变化(change)---》把图片读出来,写入到 img标签中var fileReader = new FileReader();fileReader.readAsDataURL($('#id_avatar')[0].files[0])fileReader.onload = function () {$('#id_img').attr('src', fileReader.result)}# 5 用户名失去焦点(blur)---》向后端校验# 6 form表单使用var register_form = $('#register_form').serializeArray() 转到数组中# 7 $.each(可以被循环的,function(){})# 8 错误信息渲染-__all__ 全局错误---》显示在注册后面if (key == '__all__') {$('#id_error').html(value[0])}-其他错误,显示在自己后面$('#id_' + key).next().html(value[0]).parent().addClass('has-error')-定时任务:3s后干什么setTimeout(function () {$('.error').html("").parent().removeClass('has-error')}, 3000)

2 登录功能

2.1 登录前端

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="/static/js/jquery.min.js"></script><link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
</head>
<body><div class="container-fluid"><div class="row"><div class="col-md-6 col-md-offset-3"><h1 class="text-center">登录功能</h1><form><div class="form-group"><label for="">用户名</label><input type="text" name="username" class="form-control"></div><div class="form-group"><label for="">密码</label><input type="text" name="password" class="form-control"></div><div class="form-group"><label for="">验证码</label><div class="row"><div class="col-md-6"><input type="text" name="code" class="form-control"></div><img src="/get_code/" alt="" class="col-md-6" height="35"></div></div><div class="text-center" style="margin-top: 50px"><input type="button" value="登录" class="btn btn-danger" id="id_submit"><span class="error" style="color: darkred;margin-left: 10px" id="id_error"></span></div></form></div></div>
</div></body></html>

2.2 生成验证码

# 第三方方案
https://pythonjishu.com/ljpdvvedzkqiovs/# 自己的方案
def get_code(request):# 前端显示图片 方式一# with open('./static/img/4.jpg', 'rb') as f:#     data = f.read()# return HttpResponse(data)# 方式二:自己生成一张图片,保存到本地-->打开,返回给前端# image_tmp = Image.new('RGB', (300, 38), (255, 255, 0))## with open('code.png', 'wb') as f:#     image_tmp.save(f, 'png')## with open('code.png', 'rb') as f:#     data = f.read()# return HttpResponse(data)# 方式三:借助于ByteIo,把文件内容放在内存中# image_tmp = Image.new('RGB', (300, 38), (0, 255, 0))# # 放在内存中# my_io = BytesIO()# image_tmp.save(my_io, 'png')# return HttpResponse(my_io.getvalue())# 方式四: 要在图片上写文字# image_tmp = Image.new('RGB', (300, 38), (0, 255, 0))# # 把空图片放在了画板上# draw = ImageDraw.Draw(image_tmp)# draw.text((0, 0), 'lqz')# my_io = BytesIO()# image_tmp.save(my_io, 'png')# return HttpResponse(my_io.getvalue())# 方式5 :加入字体文件# image_tmp = Image.new('RGB', (300, 38), (0, 255, 0))# # 把空图片放在了画板上# draw = ImageDraw.Draw(image_tmp)# # 加入字体# img_font = ImageFont.truetype('./static/font/xgdl.ttf', 23)# draw.text((0, 0), '西瓜大朗', fill=(0, 0, 128), font=img_font, )# my_io = BytesIO()# image_tmp.save(my_io, 'png')# return HttpResponse(my_io.getvalue())# 方式6 ,随机生成 5 大小写字母和数字,图片背景色和字的颜色每次不一样image_tmp = Image.new('RGB', (300, 38), (0, 255, 0))# 把空图片放在了画板上draw = ImageDraw.Draw(image_tmp)# 加入字体img_font = ImageFont.truetype('./static/font/xgdl.ttf', 23)draw.text((0, 0), '西瓜大朗', fill=(0, 0, 128), font=img_font, )my_io = BytesIO()image_tmp.save(my_io, 'png')return HttpResponse(my_io.getvalue())import randomdef get_random_code():code = ''for i in range(5):# 随机生成一个大写字母upper_char = chr(random.randint(65, 90))low_char = chr(random.randint(97, 122))num_char = str(random.randint(0, 9))res = random.choice([upper_char, low_char, num_char])code += resreturn codeif __name__ == '__main__':print(get_random_code())

http://www.ppmy.cn/server/31923.html

相关文章

排序算法之希尔排序(缩小增量排序)

希尔排序是插入排序的优化&#xff0c;如果不了解插入排序可以看排序算法之插入排序-CSDN博客这篇博客&#xff0c;希尔排序算法通过对原始数据集使用 gap 分组的方法&#xff0c;先将数据分组进行插入排序&#xff0c;随着排序的进行&#xff0c;逐渐减小 gap 的值&#xff0c…

爬虫自动化之drissionpage实现随时切换代理ip

目录 一、视频二、dp首次启动设置代理三、dp利用插件随时切换代理一、视频 视频直接点击学习SwitchyOmega插件使用其它二、dp首次启动设置代理 from DrissionPage import ChromiumPage, ChromiumOptions from loguru

数据库(MySQL)—— 多表查询

数据库&#xff08;MySQL&#xff09;—— 多表查询 多表关系一对多多对多一对一多表查询概述数据准备查询形式笛卡尔积 分类连接查询内连接外连接左外连接右外连接 自连接联合查询 今天我们来进入MySQL中一个非常重要的部分&#xff1a;多表查询&#xff1a; 多表关系 多表关…

vue3中reactive和ref的比较

reactiveref❌ 只支持对象和数组&#xff08;引用数据类型&#xff09;✅ 支持基本数据类型 引用数据类型✅ 在 <script> 和 <template> 中无差别使用✅ 支持基本数据类型 引用数据类型❌ 重新分配一个新对象会丢失响应性✅ 重新分配一个新对象不会失去响应能直接…

深入探索Element-UI:构建高效Web前端的利器

深入探索Element-UI&#xff1a;构建高效Web前端的利器 引言&#xff1a;前端框架的选择与Element-UI的定位一、Element-UI初探二、快速上手&#xff1a;安装与配置三、核心组件深度解析四、实用功能与进阶技巧五、性能优化与最佳实践六、实战案例分析七、与其他技术栈的集成 安…

Oracle 数据库全面升级为 23ai

从 11g 到 12c 再到 19c&#xff0c;今天&#xff0c;我们迎来了 23ai &#xff01; “ Oracle AI Vector Search allows documents, images, and relational data that are stored in mission-critical databases to be easily searched based on their conceptual content Ge…

深度学习之基于Tensorflow卷积神经网络公共区域行人人流密度可视化系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 在公共区域&#xff0c;如商场、火车站、地铁站等&#xff0c;人流密度的监控和管理对于确保公共安全…

MongoDB聚合运算符:$sum

MongoDB聚合运算符&#xff1a;$sum 文章目录 MongoDB聚合运算符&#xff1a;$sum语法使用返回的数据类型非数值或缺失字段的处理数组操作数 举例应用于$group阶段应用于$project阶段应用于$setWindowFields阶段 $sum聚合运算符返回数值的合计值&#xff0c;计算式 $sum会忽略…