1. form组件的特点
以注册为例:
a. 要有一个注册的页面,页面里面要有form表单 -->自动生成HTML代码
b. form表单要能提交数据到后端,后端要做有效性的校验 -->数据有效性校验
c. 要把校验提示信息显示到页面上 -->校验信息返回并展示,并保存原来填写的内容
2. form组件简单使用
2.1 自己生成简单form表单
2.1.1. url
url(r'^reg.html', views.reg),
2.1.2. views视图
from django import forms # 导入forms组件
class RegForm(forms.Form): # 定义一个生成form表单的类,这个类和在app的models中创建表特别类似
name = forms.CharField(max_length=32,label='用户名') # 生成输入用户名的input框,max_length最大值,label设置中文
pwd = forms.CharField(label='密码') # 生成输入密码的input框
def reg(request): # 展示网站函数
form_obj = RegForm() # 实例化上面定义的类,将实例化的对象传到html中去
return render(request,'reg.html',{'form_obj':form_obj})
2.1.3. html代码
<form action="/reg.html" method="post" novalidate> # novalidate取消浏览器做的校验
{% csrf_token %}
{{ form_obj.as_p }} # 这句代码自动生成两个input框
<input type="submit"> # 自己补一个提交按钮
</form>
2.2 数据有效性校验
2.2.1. views视图代码
from django import forms
class RegForm(forms.Form):
name = forms.CharField(
max_length=32,
label='用户名',
error_messages={
'required': '该字段不能为空',
},
)
pwd = forms.CharField(
min_length=6,
max_length=16,
label='密码',
error_messages={ # 自定义错误信息,如果验证不通过则提示
'min_length':'密码最小不能少于6位',
'max_length':'密码最长不能大于16位',
'required': '该字段不能为空',
},
)
def reg(request):
form_obj = RegForm()
if request.method == 'POST':
form_obj = RegForm(request.POST) # 如果post请求提交后,则对RegForm重新实例化,并传值进去
if form_obj.is_valid(): # 对验证结果做判断,如果验证成功则继续往下走,如果不成功则直接执行下面return代码
pass
return render(request,'reg.html',{'form_obj':form_obj})
2.2.2. html代码
<form action="/reg.html" method="post" novalidate>
{% csrf_token %}
{{ form_obj.as_p }}
{{ form_obj.errors.pwd }} # 提示自定义的错误信息,并指定提示的位置
<input type="submit">
</form>
3. form组件的详细用法
3.1 导入forms模块
from django import forms
3.2 定义一个form类
class RegForm(forms.Form)
username = forms.CharField() # 用户名对应的input框
password = forms.CharField() # 密码对应的input框
email = forms.EmailField() # 邮箱对应的input框
每个input框所能设置的参数
max_length # 最长
min_length # 最短
label # 设置中文
error_messages # 错误信息
validators # 自定义校验信息
3.3 生成HTML代码
form_obj = RegForm() # 实例化RegForm类,并把form_obj这个对象传到模板中
3.3.1 第一种写法
{{form_obj.as_p}} # 生成input框,缺点:都是用p标签包裹
3.3.2 第二种写法
用户名
{{ form_obj.name.label }}
{{ form_obj.name }}
<span class="help-block">{{ form_obj.name.errors.0 }}</span>
密码
{{ form_obj.pwd.label }} # 取类中的lable参数
{{ form_obj.pwd }} # 取类中pwd字段
<span class="help-block">{{ form_obj.pwd.errors.0 }}</span>
3.4 校验
views视图函数中
form_obj = RegForm(request.POST) form_obj.is_valid()
3.5 常用字段和字段参数
1 from django.forms import widgets 2 3 # 用户名(TextInput 文本相关) 4 name = forms.CharField( 5 max_length=32, 6 label='用户名', 7 error_messages={ 8 'required': '该字段不能为空', 9 }, 10 widget=widgets.TextInput(attrs={'class':'form-control'}), 11 ) 12 13 # 密码(PasswordInput) 14 pwd = forms.CharField( 15 min_length=6, 16 max_length=16, 17 label='密码', 18 error_messages={ # 自定义错误信息,如果验证不通过则提示 19 'min_length':'密码最小不能少于6位', 20 'max_length':'密码最长不能大于16位', 21 'required': '该字段不能为空', 22 }, 23 widget=widgets.PasswordInput(attrs={'class':'form-control'},render_value=True), # render_value=True表示如果密码错误不清空,还保留 24 ) 25 26 # 弹出下拉框并单选(Select) 27 hobby = forms.ChoiceField( 28 choices=((1,'篮球'),(2,'足球'),(3,'乒乓球'),(4,'双色球')), 29 label='爱好', 30 initial=1, 31 widget=widgets.Select(attrs={'class':'h1'}) 32 ) 33 34 # 弹出下拉框并多选(SelectMultiple) 35 hobby2 = forms.MultipleChoiceField( 36 choices=((1,'篮球'),(2,'足球'),(3,'乒乓球'),(3,'双色球')), 37 label='爱好', 38 initial=[1,3], 39 widget=widgets.SelectMultiple(attrs={'class':'h2'}) 40 ) 41 42 # 单选checkbox(CheckboxInput) 43 keep = forms.ChoiceField( 44 label='是否记住密码', 45 initial='checked', 46 widget=widgets.CheckboxInput(attrs={'class':'k1'}) 47 ) 48 49 # 多选checkbox(CheckboxSelectMultiple) 50 hobby3 = forms.MultipleChoiceField( 51 choices=((1, '篮球'), (2, '足球'), (3, '乒乓球'), (3, '双色球')), 52 label='爱好', 53 initial=[1, 3], 54 widget=widgets.CheckboxSelectMultiple(attrs={'class':'h3'}) 55 )
3.6 使用bootstrap样式
1 <head> 2 <meta charset="UTF-8"> 3 <title>Title</title> 4 <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> 5 </head> 6 <body> 7 <div class="container"> 8 <div class="row"> 9 <div class="col-md-6 col-md-offset-3"> 10 <form action="/reg.html" method="post" novalidate> 11 {% csrf_token %} 12 13 <div class="from-group"> 14 {{ form_obj.name.label }} 15 {{ form_obj.name }} 16 <span class="help-block">{{ form_obj.name.errors.0 }}</span> 17 </div> 18 <div class="from-group"> 19 {{ form_obj.pwd.label }} 20 {{ form_obj.pwd }} 21 <span class="help-block">{{ form_obj.pwd.errors.0 }}</span> 22 </div> 23 <div class="from-group"> 24 <input type="submit" class="btn btn-success" value="注册"> 25 </div> 26 </form> 27 </div> 28 </div> 29 </div> 30 </body>
3.7 在模板中form_obj对象的用法
{{ form_obj.as_p }} —— 》 生成P标签 (label 和 input)
{{ form_obj.user }} —— 》 生成input框
{{ form_obj.pwd }}
{{ form_obj.pwd.label }} ——》 对应的中文
{{ form_obj.pwd.id_for_label }} ——》 input的ID
{{ form_obj.errors }} —— 》 所有错误提示
{{ form_obj.pwd.errors }} —— 》 某个字段的所有错误提示
{{ form_obj.pwd.errors.0 }} —— 》 某个字段的第一错误提示
3.8 校验通过后
form_obj.cleaned_data # 默认提交的参数都在这个里面{'name': 'eric', 'pwd': 'pwd123', 're_pwd': 'pwd123'}
# 注册跳转函数
def reg(request):
form_obj = RegForm()
if request.method == 'POST':
form_obj = RegForm(request.POST)
if form_obj.is_valid(): # 返回布尔值,True或False
dic = form_obj.cleaned_data
models.User.objects.create(**dic)
return HttpResponse('注册成功')
return render(request,'reg.html',{'form_obj':form_obj})
3.9 自定义校验
3.9.1 正则校验手机号
from django.core.validators import RegexValidator # 导入正则校验模块
phone = forms.CharField(
label='手机号',
max_length=11,
validators=[
RegexValidator(r'^[0-9]+$','手机号必须是数字'), # 校验是不是数字
RegexValidator(r'^1[3-9][0-9]{9}$','格式错误'), # 校验格式
],
widget=widgets.TextInput(attrs={'class':'form-control'}),
error_messages={
'required':'该字段不能为空'
}
3.9.2 局部钩子校验用户名
from django.core.exceptions import ValidationError
class RegForm(forms.Form): # 在定义的forms类中去校验某个字段
...
# 校验用户名的可用性
def clean_name(self):
value = self.cleaned_data.get('name')
if '大傻逼' in value:
raise ValidationError('用户名不符合规定')
return value
3.9.3 全局钩子校验密码
from django.core.exceptions import ValidationError
class RegForm(forms.Form): # 在定义的forms类中去重写clean方法
...
# 校验两次密码的一致性
def clean(self):
pwd = self.cleaned_data.get('pwd')
re_pwd = self.cleaned_data.get('re_pwd')
if pwd != re_pwd:
self.add_errors('re_pwd','两次密码不一致')
raise ValidationError('两次密码不一致')
return self.cleaned_data
4. 解决forms.ChoiceField不更新问题
1 hobby = forms.ChoiceField( 2 choices=((1,'篮球'),(2,'足球'),(3,'乒乓球'),(4,'双色球')), 3 label='爱好', 4 initial=1, 5 widget=forms.widgets.Select(attrs={'class':'h1'}) 6 ) 7 如果choices=((1,'篮球'),(2,'足球'),(3,'乒乓球'),(4,'双色球'))里面的内容是通过数据库动态获取到的数据,例如: 8 9 choices=models.Hobby.objects.all().values_list('id','name'),那么在页面展示的时候,新添加的数据不会被显示出来,那么解决这个问题的办法如下: 10 11 # 重写父类的__init__方法 12 def __init__(self,*args,**kwargs): 13 super().__init__(*args,**kwargs) 14 self.fields['hobby'].widget.choices=models.Hobby.objects.all().values_list('id','name') # 每添加一个数据就动态刷新一次
5. 完整的注册代码
5.1 views中的代码
1 from django import forms 2 from django.forms import widgets 3 class RegForm(forms.Form): 4 # 用户名 5 name = forms.CharField( 6 max_length=6, 7 label='用户名', 8 widget=widgets.TextInput(attrs={'class':'form-control'}), 9 error_messages={ 10 'required': '该字段不能为空', 11 }, 12 ) 13 14 # 密码 15 pwd = forms.CharField( 16 min_length=6, 17 max_length=16, 18 label='密码', 19 widget=widgets.PasswordInput(attrs={'class':'form-control'},render_value=True), 20 error_messages={ 21 'min_length':'密码最小不能少于6位', 22 'max_length':'密码最长不能大于16位', 23 'required': '该字段不能为空', 24 }, 25 ) 26 27 # 确认密码 28 re_pwd = forms.CharField( 29 min_length=6, 30 max_length=16, 31 label='确认密码', 32 widget=widgets.PasswordInput(attrs={'class':'form-control'},render_value=True), 33 error_messages={ 34 'min_length':'密码最小不能少于6位', 35 'max_length':'密码最长不能大于16位', 36 'required': '该字段不能为空', 37 }, 38 ) 39 40 # 邮箱 41 email = forms.EmailField( 42 label='邮箱', 43 widget=widgets.EmailInput(attrs={'class':'form-control'}), 44 error_messages={ 45 'required': '该字段不能为空', 46 47 } 48 ) 49 50 # 手机号 51 phone = forms.CharField( 52 label='手机号', 53 max_length=11, 54 validators=[ 55 RegexValidator(r'^[0-9]+$','手机号必须是数字'), 56 RegexValidator(r'^1[3-9][0-9]{9}$','格式错误'), 57 ], 58 widget=widgets.TextInput(attrs={'class':'form-control'}), 59 error_messages={ 60 'required':'该字段不能为空' 61 } 62 63 ) 64 65 # 验证用户名是否可用 66 def clean_name(self): 67 value = self.cleaned_data.get('name') 68 if '大傻逼' in value: 69 raise ValidationError('用户名不符合规定') 70 return value 71 72 # 验证两次密码是否一致 73 def clean(self): 74 pwd = self.cleaned_data.get('pwd') 75 re_pwd = self.cleaned_data.get('re_pwd') 76 if pwd != re_pwd: 77 self.add_error('re_pwd','两次密码不一致') 78 raise ValidationError('两次密码不一致') 79 return self.cleaned_data
5.2 注册函数
1 def reg(request): 2 form_obj = RegForm() 3 if request.method == 'POST': 4 form_obj = RegForm(request.POST) 5 if form_obj.is_valid(): 6 dic = form_obj.cleaned_data 7 models.User.objects.create(**dic) 8 return HttpResponse('注册成功') 9 return render(request,'reg.html',{'form_obj':form_obj})
5.3 模板中的代码
1 <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> # 导入bootstrap样式 2 <div class="container"> 3 <div class="row"> 4 <div class="col-md-6 col-md-offset-3"> 5 <form action="/reg.html" method="post" novalidate> 6 {% csrf_token %} 7 8 <div class="from-group {% if form_obj.name.errors.0 %}has-error{% endif %}"> 9 {{ form_obj.name.label }} 10 {{ form_obj.name }} 11 <span class="help-block">{{ form_obj.name.errors.0 }}</span> 12 </div> 13 <div class="from-group {% if form_obj.pwd.errors.0 %}has-error{% endif %}"> 14 {{ form_obj.pwd.label }} 15 {{ form_obj.pwd }} 16 <span class="help-block">{{ form_obj.pwd.errors.0 }}</span> 17 </div> 18 19 <div class="from-group {% if form_obj.re_pwd.errors.0 %}has-error{% endif %}"> 20 {{ form_obj.re_pwd.label }} 21 {{ form_obj.re_pwd }} 22 <span class="help-block">{{ form_obj.re_pwd.errors.0 }}</span> 23 </div> 24 <div class="from-group {% if form_obj.email.errors.0 %}has-error{% endif %}"> 25 {{ form_obj.email.label }} 26 {{ form_obj.email }} 27 <span class="help-block">{{ form_obj.email.errors.0 }}</span> 28 </div> 29 <div class="from-group {% if form_obj.phone.errors.0 %}has-error{% endif %}"> 30 {{ form_obj.phone.label }} 31 {{ form_obj.phone }} 32 <span class="help-block">{{ form_obj.phone.errors.0 }}</span> 33 </div> 34 <div class="from-group"> 35 <input type="submit" class="btn btn-success" value="注册"> 36 </div> 37 </form> 38 </div> 39 </div> 40 </div>
浙公网安备 33010602011771号