form 组件
- 初始form组件
Django的Form主要具有一下几大功能:
- 生成HTML标签
- 验证用户数据(显示错误信息)
- HTML Form提交保留上次提交数据
- 初始化页面显示内容
- 验证功能
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" action="/form/">
<P><input type="text" name="username">{{ obj.errors.username.0 }}</P>
<P><input type="password" name="pwd">{{ obj.errors.pwd.0 }}</P>
<P><input type="text" name="age">{{ obj.errors.age.0 }}</P>
<P><input type="text" name="email">{{ obj.errors.email.0 }}</P>
<p><input type="submit"></p>
</form>
</body>
</html>
from django import forms from django.forms import fields class RegisterForm(forms.Form): username = forms.CharField(max_length=20, min_length=6, required=True, error_messages={ 'required':'用户名不能为空', 'max_length': '最大长度20', 'min_length': '最小长度6', }) pwd = forms.CharField(max_length=20, min_length=6, required=True) age = forms.IntegerField(required=True) email = forms.EmailField(required=True,error_messages={ 'invalid':'格式错误' })
from django.shortcuts import render from myform.cfrom import RegisterForm # Create your views here. def form(request): if request.method == 'GET': return render(request, 'forms/index.html') else: print(request.POST) obj = RegisterForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) else: print(obj.errors) return render(request, 'forms/index.html',{'obj':obj})
- 生成input标签功能
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form method="post" action="/form/" novalidate> <P>{{ form_obj.username }}{{ form_obj.errors.username.0 }}</P> <P>{{ form_obj.pwd }}{{ form_obj.errors.pwd.0 }}</P> <P>{{ form_obj.age }}{{ form_obj.errors.age.0 }}</P> <P>{{ form_obj.email }}{{ form_obj.errors.email.0 }}</P> <p><input type="submit"></p> </form> </body> </html>
from django.shortcuts import render
from myform.cfrom import RegisterForm
# Create your views here.
def form(request):
if request.method == 'GET':
form_obj = RegisterForm()
return render(request, 'forms/index.html', {'form_obj': form_obj})
else:
print(request.POST)
form_obj = RegisterForm(request.POST)
# obj = RegisterForm(request.POST)
if form_obj.is_valid():
print(form_obj.cleaned_data)
else:
print(form_obj.errors)
return render(request, 'forms/index.html', { 'form_obj': form_obj})
form类
from django import forms from django.forms import fields from django.forms import widgets class RegisterForm(forms.Form): username = fields.CharField( max_length=20, min_length=6, required=True, widget=widgets.TextInput(attrs={'v': 'v1', 'class': 'c1'}), initial='用户名', label='用户名', help_text='字母、数字、下划线', disabled=False, label_suffix=':', error_messages={ 'required': '用户名不能为空', 'max_length': '最大长度20', 'min_length': '最小长度6', }, ) pwd = fields.CharField( max_length=20, min_length=6, required=True, label='密码', widget=widgets.PasswordInput ) age = fields.IntegerField( required=True, max_value=200, min_value=0, label='年龄', ) email = fields.EmailField(required=True, error_messages={ 'invalid': '格式错误' }, label='邮箱', ) # 单选select city = fields.ChoiceField( choices=[ (1, '中国'), (2, '美国'), (3, '日本'), ], initial=1, label='国籍', ) # 多选select hobby = fields.MultipleChoiceField( choices=[ (1, '音乐'), (2, '把妹'), (3, '约妹'), ], initial=[1, 3] ) def __init__(self, *args, **kwargs): super(RegisterForm, self).__init__(*args, **kwargs) # 必须在self.fieLds上面 self.fields['hobby'].widget.choices = ((1, '嗨'), (2, '嗨嗨'),) # 或 # self.fields['hobby'].widget.choices = models.Classes.objects.all().value_list('id', 'caption') # 文件 img = fields.FileField( label='图片' ) # 单选的checkbox chk = fields.CharField( widget=widgets.CheckboxInput( attrs={'v': 'v1', 'class': 'c1'} ), label='居住地' ) # 多选checkbox,值为列表 dchk = fields.MultipleChoiceField( initial=[2, 1], choices=((1, '上海'), (2, '北京'),), widget=widgets.CheckboxSelectMultiple, label='曾住地' ) # 单选的radio rad = fields.CharField( widget=widgets.RadioSelect(choices=((1, '男'), (2, '女'),)), label='性别' ) # 单radio,值为字符串 rad1 = fields.ChoiceField( choices=((1, '有'), (2, '无'),), initial=2, widget=widgets.RadioSelect( attrs={'class': 'll'} ), label='媳妇' )
注意:
若是要生成 下拉菜单, 尽量不要使用 fields.ChoiceField, 实际在提交的时候总是验证错误。建议使用以下方式生成:
from django import forms from django.forms import fields from django.forms import widgets from app01 import models def get_column_list(): choices = models.ArticleColumn.objects.all().values_list('id', 'column') return choices class ArticlePostForm(forms.Form): choice = get_column_list() def __init__(self, *args, **kwargs): super(ArticlePostForm, self).__init__(*args, **kwargs) # 必须在self.fieLds上面 self.fields['column'].widget.choices = get_column_list() title = fields.CharField( required=True, error_messages={ 'required': '标题为空...' } ) column = forms.CharField( required=True, widget=widgets.Select ) body = fields.CharField( required=True, widget=widgets.Textarea, error_messages={ 'required': '内容为空...' } )
验证流程图:
流程详解
- 函数full_clean()依次调用每个field的clean()函数,该函数针对field的max_length,unique等约束进行验证,如果验证成功则返回值,否则抛出ValidationError错误。如果有值返回,则放入form的cleaned_data字典中。
- 如果每个field的内置clean()函数没有抛出ValidationError错误,则调用以clean_开头,以field名字结尾的自定义field验证函数。验证成功和失败的处理方式同步骤1。
- 最后,调用form的clean()函数——注意,这里是form的clean(),而不是field的clean()——如果clean没有错误,那么它将返回cleaned_data字典。
- 如果到这一步没有ValidationError抛出,那么cleaned_data字典就填满了有效数据。否则cleaned_data不存在,form的另外一个字典errors填上验证错误。在template中,每个field获取自己错误的方式是:{{ form.username.errors }}。
- 最后,如果有错误is_valid()返回False,否则返回True。
注意一点:自定义验证机制时:clean()和clean_<field>&()的最后必须返回验证完毕或修改后的值.
也就是说,自定义clean_fields 时,返回的是验证过的字段数据。自定义clean() 是在最后一步,要返回完整的clean_data.
# 自定义验证 验证password def clean_password(self): user_data = cleaned_data.get('password') if user_data == 'XXX': raise forms.ValidationError(u'密码太简单了') return user_data
# 验证选择婚姻是否正确 def clean_marry(self): data_list = self.cleaned_data['marry'] if len(data_list) == 2: if '0' and '1' in data_list: raise forms.ValidationError('男女选择有误!') elif '2' and '3' in data_list: raise forms.ValidationError('婚姻选择有误!') else: return data_list else: raise forms.ValidationError('请选择男女和婚姻!')
def clean(self): cleaned_data = self.cleaned_data pwd = cleaned_data['pwd'] pwd2 = cleaned_data['pwd2'] print(pwd,pwd2) if pwd != pwd2: raise forms.ValidationError('二次输入密码不匹配') return cleaned_data #注意此处一定要return clean_data,否则会报错
自定义验证规则
方式一:
rom django.forms import Form from django.forms import widgets from django.forms import fields from django.core.validators import RegexValidator class MyForm(Form): user = fields.CharField( validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')], )
方式二:
def mobile_validate(value): mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') if not mobile_re.match(value): raise ValidationError('手机号码格式错误') class PublishForm(Form): title = fields.CharField(max_length=20, min_length=5, error_messages={'required': '标题不能为空', 'min_length': '标题最少为5个字符', 'max_length': '标题最多为20个字符'}, widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': '标题5-20个字符'})) # 使用自定义验证规则 phone = fields.CharField(validators=[mobile_validate, ], error_messages={'required': '手机不能为空'}, widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'手机号码'}))
参考文档:http://www.cnblogs.com/wupeiqi/articles/6144178.html
class RegistrationForm(forms.Form): username = fields.CharField( required=True, error_messages={ 'required': '输入用户名...' } ) email = fields.EmailField( required=True, error_messages={ 'required': '输入邮箱...', 'invalid':'格式错误...' } ) password = fields.CharField( required=True, min_length=6, label='密码', widget=widgets.PasswordInput, error_messages={ 'required': '输入密码...', 'min_length': '最小长度为6...' } ) password_again = fields.CharField( required=True, widget=widgets.PasswordInput, label='确认密码', error_messages = { 'required': '输入密码...', } ) def clean_username(self): username = self.cleaned_data['username'] ret = UserInfo.objects.filter(username=username) if ret.exists(): raise forms.ValidationError('用户名已存在...') return username def clean(self): clean_data = self.cleaned_data if not self.errors: password1 = clean_data['password'] password2 = clean_data['password_again'] if password1 != password2: raise forms.ValidationError('两次密码不一致...') return clean_data