Django的Form主要具有一下几大功能:
- 生成HTML标签
- 验证用户数据(显示错误信息)
- HTML Form提交保留上次提交数据
- 初始化页面显示内容
一 通过form实现校验字段功能
模型:models.py
class UserInfo(models.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) email = models.EmaillField() tel = models.CharField(max_length=32)
模板:register.html
二 通过form组件对模板进行渲染
form校验组件
from django import formsclass UserForm(forms.Form): username = forms.CharField(min_length=4) password = forms.CharField(min_length=4) repwd = forms.CharField(min_length=4) email = forms.EmailField() tel = forms.CharField
视图函数
def register(req): if req.method == 'POST': # form = UserForm({'name':'cs', 'email': '123@qq.com', 'xxx':'harry'}) form = UserForm(req.POST) # 注意form表单的name属性值应该与forms组件字段名称一致 print(form.is_valid()) # 返回布尔值 if form.is_valid(): print(form.cleaned_data) # {"name":'cs", "email:'123@qq.com'} else: print(form.cleaned_data) print(form.errors) # {"name":["......"]}
return HttpResponse('ok')
'''if 所有的字段校验成功,则form.cleaned_data以一个字典的形式存放所有校验通过的数据 ''' return render(req, "register.html")
form组件在模板中渲染
1
1
展示错误信息
三 form组件的配置参数
Filed参数 required=Ture 是否必填 widget=None HTNL插件 label=None 用于生成Label标签显示内容 initial=None 初始值 help_text='' 帮助信息(在标签旁边显示) error_messages=None 错误信息{ 'required':'不能为空’, 'invalid':'格式错误’} show_hidden_initial=False 是否在当前插件后再加一个隐藏的具有默认值的插件(可用于两次输入是否一致) validators=[], 自定义验证规则 localize=False 是否支持本地化 disabled=False 是否可以编辑 label_suffix=None Lable内容后缀 CharField(Field) max_length=None 最大长度 min_length=None 最小长度 strip=True 是否移除用户输入空白 IntergerField(Field) max_value = None 最大值 min_value = None 最小值 DecimalField(IntergerField) max_value=None 最大值 min_value=None 最小值 max_digits=None 总长度 decimal_places=None 小数位长度 BaseTemporalField(Field) input_forats=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 { "invalid":"..."} FileField(Field) allow_empty_file=False 是否允许空文件 ChoiceField(Field) choices=(), 选项,如:choices = ((0,'上海’),(1,,'北京') required=True 是否必填 widget=None 插件,默认select插件 label=None Label内容 initial=None 初始值 help_text='', 帮助提示 TypeChoiceField(ChoiceField) coerce = lambda val: val 对选中的值进行一次转换 empty_value = '' 空的默认值 ComboFiel(Field) fields=() 使用多个验证,如下:即验证最大程度20,又验证邮箱格式 fields.ComboField(fields=[fields.CharField(max_length=20),fields.EmailField(),] GenericIPAddressField protocol='both', both,ipv4,ipv6支持的IP格式 unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.0.2.1 可以解析为192.0.0.2.1 SlugField(CharField) 数字,字母,下划线,减号(连接符)
在form中使用组件
from django.core.exceptions import NON_FIELD_ERRORS,ValidationErrorclass UserForm(forms.Form): username = forms.CharField(min_length=2, label='用户名', error_messages={ "required": "该字段不能为空"}, widget= widgets.TextInput(attrs={ 'class':"form-control"})) password = forms.CharField(min_length=4, label='密码', widget=widgets.PasswordInput(attrs={ 'class':"form-control"})) repwd = forms.CharField(min_length=4, label='重复密码', widget= widgets.TextInput(attrs={ 'class':"form-control"})) email = forms.EmailField(label='邮箱', error_messages={ "required": "该字段不能为空", "invalid":"格式输入错误"}, widget= widgets.TextInput(attrs={ 'class': "form-control"})) tel = forms.CharField(label="电话号码", error_messages={ "required": "该字段不能为空"}, widget=widgets.TextInput(attrs={ 'class': "form-control"})) def clean_username(self): val = self.cleaned_data.get("username") # 获取输入的名字 ret = UserInfo.objects.filter(name=val) # 从数据库中查询是否有该用户存在if not ret: return val else: raise ValidationError("该用户已注册") def clean_tel(self): var = self.cleaned_data.get("tel") if len(var) == 11: return var else: raise ValidationError("手机号码必须为11位!") def clean(self): pwd = self.cleaned_data.get("password") r_pwd = self.cleaned_data.get("repwd") if pwd and r_pwd: if pwd == r_pwd: return self.cleaned_data else: raise ValidationError('两次密码不一致') else: return self.cleaned_data
在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。
方式一:
1 from django.forms import Form 2 from django.forms import widgets 3 from django.forms import fields 4 from django.core.validators import RegexValidator 5 6 class MyForm(Form): 7 8 user = fields.ChoiceField( 9 # choices=((1, '上海'), (2, '北京'),),10 initial=2,11 widget=widgets.Select12 )13 14 def __init__(self, *args, **kwargs):15 super(MyForm,self).__init__(*args, **kwargs)16 # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)17 # 或18 self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')
方式二:
使用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现
1 from django import forms 2 from django.forms import fields 3 from django.forms import widgets 4 from django.forms import models as form_model 5 from django.core.exceptions import ValidationError 6 from django.core.validators import RegexValidator 7 8 class FInfo(forms.Form): 9 authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())10 # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())
四 自定义验证规则
方式一 使用字段钩子或者全局钩子
from django.core.exceptions import NON_FIELD_ERRORS,ValidationErrorclass UserForm(forms.Form): username = forms.CharField(min_length=2, label='用户名', error_messages={ "required": "该字段不能为空"}, widget=widgets.TextInput(attrs={ 'class':"form-control"})) password = forms.CharField(min_length=4, label='密码', widget=widgets.PasswordInput(attrs={ 'class':"form-control"})) repwd = forms.CharField(min_length=4, label='重复密码', widget= widgets.TextInput(attrs={ 'class':"form-control"})) email = forms.EmailField(label='邮箱', error_messages={ "required": "该字段不能为空", "invalid":"格式输入错误"}, widget=widgets.TextInput(attrs={ 'class': "form-control"})) tel = forms.CharField(label="电话号码", error_messages={ "required": "该字段不能为空"}, widget=widgets.TextInput(attrs={ 'class': "form-control"})) def clean_username(self): val = self.cleaned_data.get("username") # 获取输入的名字 ret = UserInfo.objects.filter(name=val) # 从数据库中查询是否有该用户存在if not ret: return val else: raise ValidationError("该用户已注册") def clean_tel(self): var = self.cleaned_data.get("tel") if len(var) == 11: return var else: raise ValidationError("手机号码必须为11位!") def clean(self): pwd = self.cleaned_data.get("password") r_pwd = self.cleaned_data.get("repwd") if pwd and r_pwd: if pwd == r_pwd: return self.cleaned_data else: raise ValidationError('两次密码不一致') else: return self.cleaned_data
方式二 使用
validators参数进行正则表达式匹配
1 from django.forms import Form2 from django.forms import widgets3 from django.forms import fields4 from django.core.validators import RegexValidator5 6 class MyForm(Form):7 user = fields.CharField(8 validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],9 )
通过正则表达式验证IP地址以及端口号
ipaddr_validate="^((?:(2[0-4]\d)|(25[0-5])|([01]?\d\d?))\.){3}(?:(2[0-4]\d)|(255[0-5])|([01]?\d\d?))$"port_validate='^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$'
from django.forms import Form,fieldsfrom django.forms import widgets,formsimport reipaddr_validate="^((?:(2[0-4]\d)|(25[0-5])|([01]?\d\d?))\.){3}(?:(2[0-4]\d)|(255[0-5])|([01]?\d\d?))$"port_validate='^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$'class dbinfo_create(Form): data_mode_type=fields.CharField(required=True,error_messages={ 'required':'数据库模型不能为空.'}) database_type=fields.CharField(required=True,error_messages={ 'required':'数据库类型不能为空'}) host=fields.RegexField(ipaddr_validate,required=True,error_messages={ 'required':'IP不能为空','invalid':'不合法的IP地址'}) port=fields.RegexField(port_validate,required=True,error_messages={ 'required':'端口不能为空.','invalid':'端口无效'}) # instance_nikename=fields.CharField(max_length=20,error_messages={'required':'端口不能为空.',"max_length":"标题不能超过20个字"}) db_business=fields.CharField(required=True,error_messages={ 'required':'请说明所属业务线'}) DBA=fields.CharField(required=True,error_messages={ 'required':'请说明DBA'}) responsible_person=fields.CharField(required=True, error_messages={ 'required':'请选择相关责任人!'})
五 通过Ajax提交并验证表单
function bindSubmit() { $('#submit_info').click(function () { $("#form p").removeClass('has-error'); $(".errors").html(''); var subData = new FormData(); var request_data = $('#form').serializeArray(); $.each(request_data, function (index, data) { subData.append(data.name, data.value); }); subData.append("avatar", $('#avatar')[0].files[0]); subData.append('csrfmiddlewaretoken', $("[name='csrfmiddlewaretoken']").val()); $.ajax({ url: "/register/", type: "post", processData: false, contentType: false, data: subData, dataType: 'json', success: function (data) { console.log(data.error_msg); if (!data.state) { if (data.summary_error) { $('#summary-error').html(data.summary_error) } $.each(data.error_msg, function (field, msg) { if (field == "__all__") { $('#summary-error').html(msg[0]).parent().addClass("has-error") } $('#id_' + field).next().html(msg[0]).addClass('errors').parent().addClass('has-error') }) } else { console.log(123); location.href = '/index/' } } }) }) }
class RegisterForm(forms.Form): ''' 注册form表单校验 ''' username = forms.CharField( max_length=32, error_messages={ 'required': '用户名不能为空'}, widget=widgets.TextInput(attrs={ 'class': "form-control"})) password = forms.CharField( max_length=32, error_messages={ 'required': '密码不能为空'}, widget=widgets.PasswordInput(attrs={ 'class': "form-control"})) re_pwd = forms.CharField( max_length=32, error_messages={ 'required': '密码不能为空'}, widget=widgets.PasswordInput(attrs={ 'class': "form-control"})) email = forms.EmailField( error_messages={ 'required': '邮箱不能为空'}, widget=widgets.EmailInput(attrs={ 'class': "form-control"})) check_code = forms.CharField( widget=widgets.TextInput(attrs={ 'class': "form-control"})) def clean_username(self): ''' 校验用户是否存在 :return: ''' username = self.cleaned_data.get('username') user_obj = models.UserInfo.objects.filter(username=username) if not user_obj: return username else: raise ValidationError('该用户已存在') def clean(self): ''' 校验两次输入的密码是否一致 :return: ''' password = self.cleaned_data.get('password') repwd = self.cleaned_data.get('re_pwd') if password == repwd: return self.cleaned_data else: raise ValidationError("两次密码输入不一致") def clean_email(self): ''' 校验注册邮箱是否已经注册 :return: ''' email = self.cleaned_data.get('email') user_obh = models.UserInfo.objects.filter(email=email) if not user_obh: return email else: raise ValidationError("该邮箱已被注册")
def register(request): ''' 通过ajax实现用户注册 :param request: :return: ''' response = { 'state': False, 'error_msg':"", 'summary_error': ""} if request.is_ajax(): form_obj = blog_forms.RegisterForm(request.POST) if form_obj.is_valid(): username = form_obj.cleaned_data.get('username') password = form_obj.cleaned_data.get('password') Email = form_obj.cleaned_data.get('email') valid_code = form_obj.cleaned_data.get('check_code') avatar_obj = request.FILES.get('avatar') check_valid = request.session['valid_code'] if valid_code == check_valid: extra = {} if avatar_obj: extra["avatar"] = avatar_obj blog_obj = models.Blog.objects.create( title="%s的博客" % username, site_name="%s的个人站点" % username, theme="default.css") models.UserInfo.objects.create_user(username=username, password=password, blog=blog_obj, email=Email, **extra) response['state'] = True return JsonResponse(response) else: response['summary_error'] = '验证码错误' return JsonResponse(response) else: response['error_msg'] = form_obj.errors return JsonResponse(response) elif request.method == 'GET': form_obj = blog_forms.RegisterForm() return render(request, 'register.html', { 'form_obj': form_obj})