注册页面
-用户名
-密码
-确认密码
-邮箱
-手机号
-头像
# 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 UserInfo class 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_data username = 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
注册功能前端
<!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>
注册功能后端
from django.shortcuts import render from .forms import RegisterForm from .models import UserInfo from django.http import JsonResponse # Create your views here. def 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: admin password: 123 email: [email protected] phone: 17717823244 avatar:文件 ''' form = RegisterForm(request.POST) # 使用form校验传入的数据 if form.is_valid(): # 校验通过 # 保存 data = form.cleaned_data # 把re_password 弹出 data.pop('re_password') # 把头像加入 if avatar: data['avatar'] = avatar UserInfo.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': '用户已经存在'}) else: return JsonResponse({'code': 100, 'msg': '您可以注册'})
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)
登录功能
登录前端
<!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>
生成验证码
第三方方案
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 random def 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 += res return code if __name__ == '__main__': print(get_random_code())
标签:username,登录,form,验证,bbs,校验,length,data,id From: https://www.cnblogs.com/wzh366/p/17892657.html