views:
from django.shortcuts import render, HttpResponse
from django import forms
# 先定义一个Form类
class LoginForm(forms.Form):
name = forms.CharField(
label='用户名',
initial='陌生人',
strip=True,
error_messages={
'required': '用户名不能为空',
}
)
# 密码框
password = forms.CharField(
label='密码',
min_length=6,
widget=forms.PasswordInput(render_value=True),
error_messages={
'required': '密码不能为空',
'min_length': '密码不能小于6位',
}
)
# 单选框
gender = forms.ChoiceField(
choices=[(1, '男'), (2, '女'), (3, '保密')],
label='性别',
initial=3,
widget=forms.RadioSelect(),
error_messages={
'required': '请选择性别'
}
)
# 下拉单选
hobby = forms.ChoiceField(
label='爱好',
widget=forms.Select(),
choices=((1, '篮球'), (2, '足球'), (3, '乒乓球')),
initial=2,
)
# 多选
hobby2 = forms.MultipleChoiceField(
label='爱好2',
choices=((1, '摩托车'), (2, '汽车'), (3, '游艇')),
initial=[1, 3],
widget=forms.SelectMultiple()
)
# 单选checkbox
keep = forms.ChoiceField(
label='是否记住密码',
initial='checked',
widget=forms.CheckboxInput()
)
# 多选checkbox
city = forms.ChoiceField(
label='居住城市',
choices=[(1, '北京'), (2, '天津'), (3, '上海'), (4, '武汉')],
initial=4,
widget=forms.Select()
)
# 写一个函数视图
def login(request):
form_obj = LoginForm()
if request.method == 'POST':
form_obj = LoginForm(request.POST)
if form_obj.is_valid():
pass
return render(request, 'app/login.html', {'form_obj': form_obj})
templates:
<form action="/app/login/" method="POST" novalidate>
{% csrf_token %}
<p>
<label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}label>
{{ form_obj.name }}
<span>{{ form_obj.name.errors.0 }}span>
p>
<p>
<label for="{{ form_obj.password.id_for_label }}">{{ form_obj.password.label }}label>
{{ form_obj.password }}
<span>{{ form_obj.password.errors.0 }}span>
p>
<p>
<label for="{{ form_obj.gender.id_for_label }}">{{ form_obj.gender.label }}label>
{{ form_obj.gender }}
<span>{{ form_obj.gender.errors.0 }}span>
p>
<p>
<label for="{{ form_obj.hobby.id_for_label }}">{{ form_obj.hobby.label }}label>
{{ form_obj.hobby }}
<span>{{ form_obj.hobby.errors.0 }}span>
p>
<p>
<label for="{{ form_obj.hobby2.id_for_label }}">{{ form_obj.hobby2.label }}label>
{{ form_obj.hobby2 }}
<span>{{ form_obj.hobby2.errors.0 }}span>
p>
<p>
<label for="{{ form_obj.keep.id_for_label }}">{{ form_obj.keep.label }}label>
{{ form_obj.keep }}
<span>{{ form_obj.keep.errors.0 }}span>
p>
<p>
<label for="{{ form_obj.city.id_for_label }}">{{ form_obj.city.label }}label>
{{ form_obj.city }}
<span>{{ form_obj.city.errors.0 }}span>
p>
<p>
<input type="submit" value="提交">
p>
form>
Field
required=True, 是否允许为空
widget=None, HTML插件
label=None, 用于生成Label标签或显示内容
initial=None, 初始值
help_text='', 帮助信息(在标签旁边显示)
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
validators=[], 自定义验证规则
localize=False, 是否支持本地化
disabled=False, 是否可以编辑
label_suffix=None Label内容后缀
CharField(Field)
max_length=None, 最大长度
min_length=None, 最小长度
strip=True 是否移除用户输入空白
IntegerField(Field)
max_value=None, 最大值
min_value=None, 最小值
DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 总长度
decimal_places=None, 小数位长度
DateField(BaseTemporalField) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
RegexField(CharField)
regex, 自定制正则表达式
max_length=None, 最大长度
min_length=None, 最小长度
error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'}
ChoiceField(Field)
choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默认select插件
label=None, Label内容
initial=None, 初始值
help_text='', 帮助提示
RegexValidator
验证器from django.core.validators import RegexValidator
no = forms.CharField(
label='员工编号',
validators=[RegexValidator(r'^[0-9]+', '请输入数字'), RegexValidator('^110[0-9]+$', '请以110开头')]
)
import re
from django.core.exceptions import ValidationError
def mobile_validate(value):
mobile_re = re.compile(r'^1[2356789]{1}[0-9]{9}$')
if not mobile_re.match(value):
raise ValidationError('手机号格式错误')
class LoginForm(forms.Form):
mobile = forms.CharField(
label='手机号',
validators=[mobile_validate, ],
error_messages={
'required': '手机号不能为空',
}
)
在Fom类中定义 clean_字段名()
方法,就能够实现对特定字段进行校验
class LoginForm(forms.Form):
description = forms.CharField(
label='内容描述',
initial='暂无描述',
min_length=4,
error_messages={
'required': '不能为空',
'invalid': '格式错误',
'min_length': '最少评论4个字'
}
)
def clean_description(self):
value = self.cleaned_data.get('description')
if '666' in value:
raise ValidationError('请不要喊666')
else:
return value
在Fom类中定义clean()
方法,就能够实现对字段进行全局校验
class LoginForm(forms.Form):
# 密码框
password = forms.CharField(
label='密码',
min_length=6,
widget=forms.PasswordInput(),
error_messages={
'required': '密码不能为空',
'min_length': '密码不能小于6位',
}
)
repassword = forms.CharField(
label='请再次输入密码',
min_length=6,
widget=forms.PasswordInput(),
error_messages={
'required': '密码不能为空',
'min_length': '密码不能小于6位',
}
)
def clean(self):
password_value = self.cleaned_data.get('password')
repassword_value = self.cleaned_data.get('repassword')
if password_value == repassword_value:
return self.cleaned_data
else:
self.add_error('repassword', '两次密码不一致')
在执行form_obj.is_valid()
进行判断
进入is_valid
方法
def is_valid(self):
"""
Returns True if the form has no errors. Otherwise, False. If errors are
being ignored, returns False.
"""
return self.is_bound and not self.errors
self.is_bound
判断是否有数据
self.errors
判断是否有错误信息
进入errors
属性方法
@property
def errors(self):
"Returns an ErrorDict for the data provided for the form"
if self._errors is None:
self.full_clean()
return self._errors
进入full_clean
方法
self._errors
存放错误信息
cleaned_data
存放验证通过的数据
def full_clean(self):
"""
Cleans all of self.data and populates self._errors and
self.cleaned_data.
"""
self._errors = ErrorDict()
if not self.is_bound: # Stop further processing.
return
self.cleaned_data = {}
# If the form is permitted to be empty, and none of the form data has
# changed from the initial data, short circuit any validation.
if self.empty_permitted and not self.has_changed():
return
self._clean_fields()
self._clean_form()
self._post_clean()
执行_clean_fields
方法,循环每个字段,分别校验
def _clean_fields(self):
for name, field in self.fields.items():
# value_from_datadict() gets the data from the data dictionaries.
# Each widget type knows how to retrieve its own data, because some
# widgets split data over several HTML fields.
if field.disabled:
value = self.get_initial_for_field(field, name)
else:
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, FileField):
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self.add_error(name, e)
执行_clean_form
方法
def _clean_form(self):
try:
cleaned_data = self.clean()
except ValidationError as e:
self.add_error(None, e)
else:
if cleaned_data is not None:
self.cleaned_data = cleaned_data