forms组件(注册用户讲解)(自定义校验字段,渲染模板功能,渲染错误信息功能,局部钩子渲染错误信息,全局钩子渲染错误信息),基于forms组件写的注册系统(前台前台加载文件)
forms组件
from django import forms from django.forms import widgets from django.core.exceptions import ValidationError
class Myforms(forms.Form): # 继承Form类 name = forms.CharField(max_length=8,min_length=3 ,label='用户名', error_messages={'max_length':"最长是8","min_length":'最短是3','required':'这个必须填'}, # 错误信息变成中文 widget=widgets.TextInput(attrs={"class":"form-control","id":"name"}) # 渲染模板输入框 ) pwd = forms.CharField(max_length=8,min_length=3,label='密码' ,required=True, error_messages={'max_length':"最长是8","min_length":'最短是3','required':'这个必须填'}, widget=widgets.PasswordInput(attrs={"class":"form-control","id":"pwd"}) ) re_pwd = forms.CharField(max_length=8, min_length=3, label='确认密码', required=True, error_messages={'max_length': "最长是8", "min_length": '最短是3', 'required': '这个必须填'}, widget=widgets.PasswordInput(attrs={"class":"form-control","id":"re_pwd"}) ) email = forms.EmailField(label='邮箱',error_messages={'required':'这个必须填','invalid':'不符合邮箱格式'}, widget=widgets.EmailInput(attrs={"class":"form-control","id":"email"})
# 局部钩子(写在自定义的form类里,校验单独字段,自定义2次校验)
# 单个字段的二次校验 def clean_name(self): # 函数名为clean + 校验的字段名 import re data = self.cleaned_data.get("name") if not re.match('^[0-9]', data): return data raise ValidationError("不能以数字开头") # 抛django内置的异常
# 全局钩子(写在自定义的form类里,校验多个字段,自定义2次校验)
# 所有字段的二次校验
def clean(self): # 函数名只能为clean if self.cleaned_data: pwd = self.cleaned_data.get("pwd") re_pwd = self.cleaned_data.get("re_pwd") if pwd != re_pwd: raise ValidationError("两次密码不一致") # 抛django内置的异常 return self.cleaned_data
校验字段功能
# 渲染模板(数据) forms_obj = Check_forms() # 生成forms渲染表单对象 forms_obj.username.errors.0 # 单个字段的错误信息 forms_obj.username.label # 字段名 forms_obj.username.html_name # 字段名 forms_obj.username.auto_id # 字段名 # forms校验(数据) forms_user = Check_forms({"name":"lxx","pwd":"123") # 开始校验字段 forms_user.is_valid() # 是否校验通过 forms_user.cleared_data # 校验通过的数据
forms_user.errors # 错误信息
forms_user.errors[0] # 取其中一条
forms_user.errors['__all__'][0] # 全局钩子错误信息
渲染模板的三种方式 [ 推荐第二种 ]
# 第一种:通过校验对象 <p>用户名:{{ myform.name }}</p> <p>密码: {{ myform.pwd }}</p> <p>密码<input type="text" name="re_pwd"></p> <p>邮箱:{{ myform.email }}</p> <input type="submit" value="提交"> # 第二种:for循环校验对象 (推荐) {% for foo in myform %} <p>{{ foo.label }}{{ foo }}</p> {% endfor %} <input type="submit" value="提交"> # 第三种: <p>{{ myform.as_p }}</p> <p>{{ myform.as_ul }}</p> <input type="submit" value="提交">
基于forms组件写的注册系统
要校验的字段
from django import forms from django.forms import widgets from django.core.exceptions import ValidationError from blog import models class RegForm(forms.Form): username = forms.CharField(max_length=18, min_length=2, label='用户名', widget=widgets.TextInput(attrs={'class': 'form-control'}) ) password = forms.CharField(max_length=18, min_length=2, label='密码', widget=widgets.PasswordInput(attrs={'class': 'form-control'})) re_password = forms.CharField(max_length=18, min_length=2, label='确认密码', widget=widgets.PasswordInput(attrs={'class': 'form-control'})) email = forms.EmailField(label='邮箱', widget=widgets.TextInput(attrs={'class': 'form-control'})) # 局部校验钩子函数 def clean_username(self): name = self.cleaned_data.get('username') # 去数据库校验 ret = models.UserInfo.objects.filter(username=name).first() if ret: raise ValidationError('用户名已存在') return name # 全局校验钩子函数 def clean(self): pwd = self.cleaned_data.get('password') re_pwd = self.cleaned_data.get('re_password') if pwd and re_pwd: if pwd == re_pwd: return self.cleaned_data else: raise ValidationError('两次密码不一致')
views文件 后台校验逻辑
def register(request): if request.method == 'GET': myform = myforms.MyForm() # Forms组件渲染登陆模板(可以不用) return render(request,'register.html',{'myform':myform}) elif request.method == 'POST': response = { 'user':None,'msg':None } # 设置好返回前台的形式 mas 对应错误信息 user 对应是否登录成功 myform = myforms.MyForm(request.POST) # 传入需要校验的数据,必须是字典 if myform.is_valid(): # 校验通过 dic = myform.cleaned_data # 校验是否通过 dic.pop('re_pwd') # 删除 确认密码字段 user = models.UserInfo.objects.create_user(username=dic.get('username'), password=dic.get('pwd'), email= dic.get('email'),) response['user'] = user.username response['img'] = '注册成功' else: response['msg'] = myform.errors return JsonResponse(response)
注册系统前台代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"> <script src="/static/jquery-3.3.1.js"></script> <title>注册页面</title> <style> #my_file { display: none; } #all_error { color: red; position: relative; margin: 0; } .span_errpr { color: red; float: right; } </style> </head> <body> <div class="container-fluid"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h1>博客注册系统</h1> <form action="" id="form"> {% csrf_token %} {% for foo in myform %} <div class="form-group"> <label for="{{ foo.auto_id }}"> {{ foo.label }} </label> {{ foo }} </div> {% endfor %} <label for="my_file">上传 <img src="/static/img/default.png" alt="" width="60" height="60" id="img_file"> </label> <input type="file" id='my_file'> </form> <div> {# 全局错误信息 #} <span id="all_error" class="pull-left" ></span> <div class="pull-right"> <button id="btn">注册</button> </div> </div> </div> </div> </div> </body> <script> $('#my_file').change(function () { {# 把文件取出来 #} var file_obj = $('#my_file')[0].files[0]; {# 生成文件阅读器 #} var filereader = new FileReader(); {# 把文件读到阅读器中 #} filereader.readAsDataURL(file_obj); {# 文件全部加载完毕以后的结果,赋值给其他标签的属性 js修改属性 #} filereader.onload = function () { $('#img_file').attr('src',filereader.result) } }); $("#btn").click(function () { var formdata = new FormData(); {#formdata.append( 'file', $('#my_file')[0].files[0]);#} {#formdata.append( 'pwd', $('#id_pwd').val());#} {#formdata.append( 'name', $('#id_name').val());#} {#formdata.append( 'email', $('#id_email').val());#} {#formdata.append( 're_pwd', $('#id_re_pwd').val());#} {# 相当于把 form 表单里所有的值放入一个数组里 #} var arr = $('#form').serializeArray(); {# jq循环 #} $.each(arr,function (k ,v) { {#console.log(k);#} console.log(v); formdata.append(v.name,v.value) }); $.ajax({ url: '/register/', type: 'post', processData:false, contentType:false, data: formdata, success: function (data) { if (data.user) { location.href = '/index/' } else { $('.span_errpr').remove(); {#console.log(data);#} {#console.log(data.msg);#} for ( k in data.msg ) { {# 判断是否是全局信息 #} if (k === '__all__'){ {# js修改标签内容 #} $('#all_error').text(data.msg[k]) } else { {# js生成标签 #} $('#'+'id_'+k).before('<span class="span_errpr">' + data.msg[k] + '</span>' ) } } } } }) }) </script>