本文共 12006 字,大约阅读时间需要 40 分钟。
这里不是验证用户名密码是否正确,这部分内容之前已经讲过了。这里要验证的是数据格式,这步验证是在收到请求后先执行的验证。只有数据格式验证通过,才会验证用户名密码是否正确。如果数据格式验证不通过,则返回错误信息。
讲师的博客地址:先写一个form表单,host.html:
然后导入验证的模块写一个类:
from django import formsclass FM(forms.Form): # 变量的字段名匹配form表单里的name属性的值,必须一样 hostname = forms.CharField() ip = forms.GenericIPAddressField(protocol='ipv4') port = forms.IntegerField() email = forms.EmailField() # 上面只有这么几个,如果提交的数据有很多,那么其他数据都不收(丢弃)
然后是在处理函数里,通过这个类进行验证:
def host(request): if request.method == 'GET': return render(request, 'host.html') if request.method == 'POST': obj = FM(request.POST) # 实例化,把POST的数据传入 res = obj.is_valid() # 获取结果 print(res) # 验证通过是True,不通过则是False if res: print(obj.cleaned_data) # 这是一个原生的字典,里面就是提交来的数据 return HttpResponse('OK') else: print(obj.errors) # 这里是一串html的列表的代码 print(type(str(obj.errors))) # 这里的str方法居然是django提供的,变成() print(obj.errors.as_json()) # 也可以拿到JSON的格式 return HttpResponse(str(obj.errors)) # 通过str方法后,页面上会直接按html代码处理
现在可以打开页面测试效果。
验证通过,obj.cleaned_data 里就是合法的数据的字典,可以进行后续的操作。验证不通过,obj.errors是错误信息(html的格式,一个ul无序列表),也可以通过 obj.errors.as_json() 获取一个JSON格式的错误信息:{"hostname": [{"message": "This field is required.", "code": "required"}], "ip": [{"message": "Enter a valid IPv4 address.", "code": "invalid"}], "port": [{"message": "Enter a whole number.", "code": "invalid"}], "email": [{"message": "Enter a valid email address.", "code": "invalid"}]}
错误信息包括,错误类型(code)和错误信息(message),这里的错误信息也可以自定义,我要中文的。
通过参数error_messages设置自定义的错误信息,code的值就是key,然后把你希望的内容填在value里:
from django import formsclass FM(forms.Form): # 变量的字段名匹配form表单里的name属性的值,必须一样 hostname = forms.CharField( max_length=12, min_length=6, error_messages={'required': "设备名不能为空", 'max_length': "设备名太长,不能超过12", 'min_length': "设备名太短,不能小于6"}) ip = forms.GenericIPAddressField(protocol='ipv4') port = forms.IntegerField() email = forms.EmailField(error_messages={'required': "邮箱不能为空", 'invalid': "邮箱格式错误"})
现在使用render方法,把错误信息返回给页面。所有内容都在obj里,把整个obj返回:
return render(request, 'host.html', {'obj': obj})
通过模板语言获取错误信息。这里注意最后要在.0拿到的才是错误信息的内容
还有一个问题是,你一点提交你之前在input里填的内容会被清空。这样不好。
上面讲的都是form组件的一个功能,其实django的form组件主要是完成下面的2个功能的
form组件的2大功能:自动生成input标签
用下面的方法可以自动生成input标签。form标签这里加上了一个novalidate属性,是为了禁用客户端的表单验证功能,可以直接看到服务端返回的验证信息。换句话说,就是自动生成的标签还帮我么加上了简单的客户端的初步验证的功能:上面只是生成了input标签,里面没有设置placeholder,如果需要加上自定义属性后面会讲。
这里还有这些常用的变量:<label for="id_hostname">Hostname:</label>
,一个for一个value,可以用下面2个变量单独拿到这2个值。这里处理函数要注意,因为GET请求也需要返回obj对象(但是GET里不用填参数)给页面了,所以要做如下的修改:
def host(request): if request.method == 'GET': obj = FM() # 这里也需要创建一个对象,因为需要它生成标签,但是不需要传参数 return render(request, 'host.html', {'obj': obj}) if request.method == 'POST': obj = FM(request.POST) # 实例化,把POST的数据传入 res = obj.is_valid() # 获取结果 if res: print(obj.cleaned_data) return HttpResponse('OK') else: # return HttpResponse(str(obj.errors)) return render(request, 'host.html', {'obj': obj})
自动生成表单
还是推荐用上面的,这个可定制性太差了。form标签自己写,submit自己写,其他的都不用写。有3中方式:继续看form组件的2大功能:
插件可以定义标签的类型,默认是文本框,可以改变成多行文本、单选复选,总之是所有的input标签的类型。
插件还可以定义标签的属性,这样就实现了自定义样式。定义前先要导入插件的模块,from django.forms import widgetsfrom django.forms import Form # 这个是要继承的类from django.forms import fields # 学到这里,字段导入这个模块from django.forms import widgets # 这个模块是插件class FM(forms.Form): # 变量的字段名匹配form表单里的name属性的值,必须一样 hostname = fields.CharField( max_length=12, min_length=6, error_messages={'required': "设备名不能为空", 'max_length': "设备名太长,不能超过12", 'min_length': "设备名太短,不能小于6"}) ip = fields.GenericIPAddressField( widget=widgets.Textarea, # 这里改成多行文本,不定义样式后面就不用跟括号 protocol='ipv4') port = fields.IntegerField( widget=widgets.TextInput(attrs={'class': 'c1'}) # 后面跟括号,写上你要自定义的属性 ) email = fields.EmailField(error_messages={'required': "邮箱不能为空", 'invalid': "邮箱格式错误"})
学到这里,之前导入模块的方式不太好,明确导入需要的模块。
导入from django.forms import Form
模块,这个是要继承的类导入 from django.forms import fields
模块来定义字段,这个 fields 是所有字段类型的基类。开始用的是 forms.CharField
都改成 fields.CharField
。导入 from django.forms import widgets
模块来定义插件。如果只定义类型,后面就不用加括号。如果需要自定义属性,就在后面加括号,attrs里以字典的形式写上各种自定义的属性。密码的input框类型,可以用这个插件 widget=widgets.PasswordInput,
。所有的验证类型查看文件 django\forms\fields.py ,里面有这么多种验证类型。第一个Field是基类,后面的都是继承这个Field的子类或者是孙子类: __all__ = ( 'Field', 'CharField', 'IntegerField', 'DateField', 'TimeField', 'DateTimeField', 'DurationField', 'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField', 'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField', 'ComboField', 'MultiValueField', 'FloatField', 'DecimalField', 'SplitDateTimeField', 'GenericIPAddressField', 'FilePathField', 'SlugField', 'TypedChoiceField', 'TypedMultipleChoiceField', 'UUIDField',)
创建Form类时,主要涉及到【字段】和【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML。
Django内置字段如下:widget=widgets.Select
,还可以SelectMultiple(复选select),widgets.RadioSelect(单选),CheckboxSelectMultiple(多选)fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
Field 属性 validators,自定义验证规则
from django.forms import Formfrom django.core.validators import RegexValidatorclass MyForm(Form): mobile = fields.CharField( validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')], )
FilePathField(ChoiceField)
把你把一个文件夹下的所有的文件列举出来,然后选一个提交:from django.forms import Formfrom django.forms import fieldsclass FM(Form): folder = fields.FilePathField(path='app01')def folder(request): obj = FM() return render(request, 'folder.html', {'obj': obj})
模板语言会自动生成下拉列表:
{ { obj.folder }}
页面上会生成一个下拉框,里面显示的是文件名,后面有个提交按钮。提交的是文件路径。
下面这些都是内置的插件。插件后面都可以加上 (attrs={'key': 'value'})
进行自定制属性:
在Web应用程序中开发编写功能时,时常用到获取数据库中的数据并将值初始化在HTML中的标签上。
获取数据后把数据放在一个字典里。如果是数据库查询,ORM可以直接获取字典形式的数据。之前GET请求里用的是obj = FM()
,相当于传入空值,现在可以把字典作为参数传入 obj = FM(initial=dic)
。这样页面上使用Form生成的html标签里就有字典里的值了。直接修改之前的例子,先准备好一个有数据的字典(这里就不查数据库了)。然后只需要传入这个字典就好了,别的都不用改。这样生成的页面里的输入框是会把字典里的值填上的: # 实际使用的时候,通过ORM可以直接获取到一条记录的字典dic = { 'hostname': "HOST1", 'ip': '192.168.2.1', 'port': 23, 'email': 'py@dj.cn'}def host(request): if request.method == 'GET': # obj = FM() # 之前是不传参数的,所有输入框里都是空的 obj = FM(initial=dic) # 现在传入参数,输入框里就会把字典里的值作为默认值填上 return render(request, 'host.html', {'obj': obj}) if request.method == 'POST': obj = FM(request.POST) # 实例化,把POST的数据传入 res = obj.is_valid() # 获取结果 if res: print(obj.cleaned_data) return HttpResponse('OK') else: # return HttpResponse(str(obj.errors)) return render(request, 'host.html', {'obj': obj})
直接像这样 obj = FM(dic)
传字典也是可以的,或者这样 obj = FM({'hostname': "HOST1", 'ip': '192.168.2.1',})
。至少效果是一样的。这里看着按位置参数传递的话,参数不是传给initial的。
上面都是用form表单来提交的。之前还学过用Ajax提交。提交没有问题,但是Ajax提交返回的要求是字符串。或者是字典、列表可以用JSON序列化为字符串。但是这里返回的是 obj = FM()
对象,如何序列化成字符串返回给Ajax?
转载于:https://blog.51cto.com/steed/2104396