forms组件
一、校验字段功能
针对一个实例:注册用户讲解。
模型:使用django的auth_user表
模板:register.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post"> {% csrf_token %} <div> <label for="user">用户名</label> <p><input type="text" name="user" id="user"></p> </div> <div> <label for="pwd">密码</label> <p><input type="password" name="pwd" id="pwd"></p> </div> <div> <label for="r_pwd">确认密码</label> <p><input type="password" name="r_pwd" id="r_pwd"></p> </div> <div> <label for="email">邮箱</label> <p><input type="email" name="email" id="email"></p> </div> <input type="submit"> </form> </body> </html>
视图函数:register
class UserForm(forms.Form): #校验规则 user = forms.CharField(min_length=5, error_messages={'required':'该字段不能为空'}, label='用户名', widget=widgets.TextInput(attrs={'class':'input','id':'user'}) ) pwd = forms.CharField(min_length=5, error_messages={'required':'该字段不能为空'}, label='密码', widget=widgets.PasswordInput(attrs={'class':'input','id':'pwd'}) ) r_pwd = forms.CharField(min_length=5, error_messages={'required': '该字段不能为空'}, label='确认密码', widget=widgets.PasswordInput(attrs={'class': 'input','id':'r_pwd'}) ) email = forms.EmailField(error_messages={'invalid':'邮箱格式错误','required': '该字段不能为空'}, label='邮箱', widget=widgets.EmailInput(attrs={'class':'input','id':'email'}) ) #自定义错误,进行第二次过滤(局部钩子) def clean_user(self): val=self.cleaned_data.get('user') print(val) # user_obj = auth.authenticate(username=val) ret = User.objects.filter(username=val) print(ret) if not ret: #数据库找不到这个用户 return val else: raise ValidationError('用户已存在!') def clean_pwd(self): val=self.cleaned_data.get('pwd') if val.isdigit(): raise ValidationError('密码不能是纯数字!') else: return val def clean_email(self): val=self.cleaned_data.get('email') if not val.endswith('163.com'): raise ValidationError('邮箱必须是163邮箱!') else: return val def clean(self): #全局钩子,什么情况下都会执行 pwd=self.cleaned_data.get('pwd') r_pwd=self.cleaned_data.get('r_pwd') if pwd and r_pwd: if pwd==r_pwd: return self.cleaned_data else: raise ValidationError('两次密码不一致!') else: return self.cleaned_data
逻辑代码:
def register(request): import json if request.method == 'GET': form = UserForm() return render(request, 'reg.html',locals()) else: form = UserForm(request.POST) if form.is_valid(): #对数据进行校验 user = form.cleaned_data.get('user') #form.cleaned_data为一个字典,里面存储着符合条件的字段 pwd = form.cleaned_data.get('pwd') email = form.cleaned_data.get('email') user_obj = User.objects.create_user(username=user,password=pwd,email=email) auth.login(request, user_obj) return HttpResponse('OK') else: errors=form.errors #form.errors为一个字典,键是错误的字段,值是相关的错误的信息 return HttpResponse(json.dumps(errors))
二、渲染标签功能
方式一:
<form action="" method="post"> //form表单和submit按钮需要自己写 {% csrf_token %} {{ form.as_p }} <input type="submit"> </form>
方式二:
<form action="" method="post" novalidate> {% csrf_token %} <p> 用户名 {{ form.user }}<span class="error">{{ errors.user.0 }}</span> </p> //{{ form.user }}渲染出user的input标签 <p>密码 {{ form.pwd }}<span class="error">{{ errors.pwd.0 }}</span></p> <p>确认密码 {{ form.r_pwd }}<span class="error">{{ errors.r_pwd.0 }}</span></p> <p>邮箱 {{ form.email }}<span class="error">{{ errors.email.0 }}</span></p> <input type="submit" class="btn btn-success pull-right"> </form>
方式三:
<form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="">{{ field.label }}</label> {{ field }} <span class="error">{{ field.errors.0 }}</span> {# //{{ field }}为渲染出来的input标签#} {% if field.label == "确认密码" %} <span class="error">{{ g_error|default:"" }}</span> {% endif %} </div> {% endfor %} <input type="submit" class="btn btn-success pull-right"> </form>
三、显示错误与重置输入信息功能
方式一:form表单操作
视图:
def reg(request): if request.method=="POST": print(request.POST) # 数据校验 form=UserForm(request.POST) if form.is_valid(): UserInfo.objects.create(**form.cleaned_data) return HttpResponse("OK") else: # print(form.cleaned_data) # print(form.errors) # {"user":["",]} # print(form.errors.get("user")[0]) # {"user":["",]} errors=form.errors if form.errors.get("__all__"): g_error=form.errors.get("__all__")[0] return render(request, "reg.html",locals()) else: form=UserForm() return render(request,"reg.html",locals())
模板:
<form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="">{{ field.label }}</label> {{ field }} <span class="error">{{ field.errors.0 }}</span> {# //{{ field }}为渲染出来的input标签#} {% if field.label == "确认密码" %} <span class="error">{{ g_error|default:"" }}</span> {% endif %} </div> {% endfor %} <input type="submit" class="btn btn-success pull-right"> </form>
方式二:Ajax操作
视图:
def register(request): import json if request.method == 'GET': form = UserForm() return render(request, 'reg.html',locals()) else: form = UserForm(request.POST) if form.is_valid(): #对数据进行校验 user = form.cleaned_data.get('user') #form.cleaned_data为一个字典,里面存储着符合条件的字段 pwd = form.cleaned_data.get('pwd') email = form.cleaned_data.get('email') user_obj = User.objects.create_user(username=user,password=pwd,email=email) auth.login(request, user_obj) return HttpResponse('OK') else: errors=form.errors #form.errors为一个字典,键是错误的字段,值是相关的错误的信息 return HttpResponse(json.dumps(errors))
模板:
{% for field in form %} <div class="group"> <label for="" class="label">{{ field.label }}</label> {{ field }}<span class="error"></span> </div> {% endfor %} <div class="group"> <input type="submit" class="button" value="注册" id="zhuce"> </div>
<script src="/static/js/jquery.js"></script> <script> $('#zhuce').click(function () { $.ajax({ url:'/register/', type:'post', data:{ user:$('#user').val(), pwd:$('#pwd').val(), r_pwd:$('#r_pwd').val(), email:$('#email').val() }, success:function (response) { if(response=='OK'){ location.href='/books/' } else{ $.each(JSON.parse(response),function (i,j) { if(i=='user'){ $('#user').next().html(j[0]) }if (i=='pwd'){ $('#pwd').next().html(j[0]) }if (i=='r_pwd'){ $('#r_pwd').next().html(j[0]) }if (i=='email'){ $('#email').next().html(j[0]) }if(i=='__all__'){ $('#r_pwd').next().html(j[0]) } }); } } }) }); </script>
或者更简单一些:
视图:
def register(request): from django.http import JsonResponse if request.method == 'GET': form = UserForm() return render(request, 'reg.html',locals()) else: form = UserForm(request.POST) res = {'user':None,'err_msg':''} if form.is_valid(): #对数据进行校验 user = form.cleaned_data.get('user') #form.cleaned_data为一个字典,里面存储着符合条件的字段 res['user'] = user pwd = form.cleaned_data.get('pwd') email = form.cleaned_data.get('email') user_obj = User.objects.create_user(username=user,password=pwd,email=email) auth.login(request, user_obj) else: errors=form.errors #form.errors为一个字典,键是错误的字段,值是相关的错误的信息 res['err_msg'] = errors return JsonResponse(res) #JsonResponse对字典进行序列化,底层封装了HttpResponse,相关信息Ajax接收后会自动反序列化,不需要再人为的反序列化.
模板:
<script src="/static/js/jquery.js"></script> <script> $('#zhuce').click(function () { $.ajax({ url: '/register/', type: 'post', data: { user: $('#user').val(), pwd: $('#pwd').val(), r_pwd: $('#r_pwd').val(), email: $('#email').val() }, success: function (response) { //ajax已经自动将序列化的字典进行了反序列化 if (response.user) { location.href = '/books/' } else { $('.error').html(''); $.each(response.err_msg,function (i,j) { $('#'+i).next().html(j[0]) }); } } }) }) <script/>
四、局部钩子与全局钩子
参见 一、校验字段功能 视图部分代码,需要注意局部钩子只有在满足第一个条件之后才会执行,如果在第一个条件不满足就不会进一步执行局部钩子代码,相反,全局钩子什么时候都会 执行。
五、扩展
如何往django自带的auth_user表中添加新的字段,如手机号?
models.py
from django.contrib.auth.models import AbstractUserclass
UserInfo(AbstractUser): #相当于继承了auth_user表 tel = models.CharField(max_length=32)
settings
AUTH_USER_MODEL = 'app01.UserInfo' #app01自定义,为UserInfo所在的app
随后可执行:python manage.py makemigrations
python manage.py migrate
这时django自带的auth_user表将会消失,取而代之的是app01_userinfo