Django之Form组件(一)
Django的Form主要具有一下几大功能:
生成HTML标签
验证用户数据(显示错误信息)
HTML Form提交保留上次提交数据
初始化页面显示内容
基本操作:字段验证并显示错误信息,渲染标签(生成HTML标签),保留上次提交数据
1 from django.shortcuts import render,HttpResponse,redirect 2 from django import forms #引入模块 3 from django.forms import fields 4 5 6 class FiForm(forms.Form): #必须继承forms.Form
7 user=fields.CharField(max_length=12,min_length=6,required=True, 8 error_messages={ 9 'required': '用户名不能为空', 10 'max_length': '用户名最大12位', 11 'min_length':'用户名最少6位', 12 }) 13 14 pwd=fields.CharField(min_length=12,required=True, 15 error_messages={ 16 'required': '密码不能为空', 17 'min_length': '密码最少12位', 18 19 }) 20 age=fields.IntegerField(required=True, 21 error_messages={ 22 'required': '年龄不能为空', 23 }) 24 email=fields.EmailField(required=True, 25 error_messages={ 26 'required':'邮箱格式不对' 27 }) 28 29 def login1(request): 30 31 if request.method =='GET': 32 obj=FiForm()#第一次生成FiForm对象,没有传参,生成HTML代码 33 return render(request,"login1.html",{'obj':obj}) 34 else: 35 u=request.POST.get('user') #不能为空,长度6-12 36 p=request.POST.get('passwd') #不能为空,长度12 37 e = request.POST.get('email')#不能为空,邮箱格式 38 a = request.POST.get('age')#不能为空,数字类型 39 print(u,p,e,a) 40 #检查是否为空 41 #检查格式 42 obj=FiForm(request.POST) #传入数据进行字段验证,form表单的name属性值应该与forms组件的字段名称一致,不一致的键值不会去做校验。
43 #是否全部验证成功,返回true或false 44 if obj.is_valid(): 45 经过验证后得到的的数据 46 print('验证成功',obj.cleaned_data) 47 else: 48 print('验证失败',obj.errors) # 字段不符合要求的对应的键作为键,错误信息作为值 <ul class="errorlist"><li>r_pwd<ul class="errorlist">... 49 return render(request,"login1.html",{'obj':obj}) #传入obj对象
分析:
(1)引入模块
from django import forms from django.forms import fields
(2)生成验证类
class FiForm(forms.Form): user=fields.CharField(max_length=12,min_length=6,required=True, error_messages={ 'required': '用户名不能为空', 'max_length': '用户名最大12位', 'min_length':'用户名最少6位', }) pwd=fields.CharField(min_length=12,required=True, error_messages={ 'required': '密码不能为空', 'min_length': '密码最少12位', }) age=fields.IntegerField(required=True, error_messages={ 'required': '年龄不能为空', }) email=fields.EmailField(required=True, error_messages={ 'required':'邮箱格式不对' })
(3)生成forms对象,需要注意的是给对象传入字典就可以做一个个值的校验:
例:form = UserForm({"name": "yuan", "email": "123@qq.com", "xxx":"alex"})
obj=FiForm(request.POST)
注意:form表单的name属性值应该与forms组件的字段名称一致,不一致的键值不会去做校验
(4)
form.is_valid() :做校验返回布尔值的,所有都通过才返回True,否则返回False。与forms组件字段无关的键值不影响返回结果。
form.cleaned_data:字段值符合要求的放在cleaned_data中。字典数据类型。
form.errors:字段不符合要求的对应的键作为键,错误信息作为值。虽然返回结果比较复杂,但依然是字典数据类型,可以通过form.errors.get(“不符合的键”)来拿到键值,键值为列表数据类型。因此可以通过form.errors.get("不符合键")[0]拿到错误信息。
form.errors.get("pwd") #在后端取
{{ obj.errors.user.0 }} #在前端取,obj为传过去的对象。
(5)去掉浏览器的验证机制
如果你的表单包含URLField``EmailField 或其它整数字段类型,Django 将使用number、url和 email 这样的HTML5 输入类型。 默认情况下,浏览器可能会对这些字段进行它们自身的验证,这些验证可能比Django 的验证更严格。 如果你想禁用这个行为,请设置form 标签的novalidate属性,
或者指定一个不同的字段,如TextInput
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <form action="/login1/" method="POST"> 9 {% csrf_token %} 10 <!--<p>用户名:<input type="text" name="user">{{ obj.errors.user.0 }}</p>--> 11 <!--<p>密码:<input type="password" name="passwd">{{ obj.errors.pwd.0 }}</p>--> 12 <!--<p>邮箱:<input type="text" name="email">{{ obj.errors.email.0 }}</p>--> 13 <!--<p>年龄:<input type="text" name="age">{{ obj.errors.age.0 }}</p>--> 14 <p>用户名:{{ obj.user }}{{ obj.errors.user.0 }}</p> 15 <p>密码:{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p> 16 <p>邮箱:{{ obj.email }}{{ obj.errors.email.0 }}</p> 17 <p>年龄:{{ obj.age }}{{ obj.errors.age.0 }}</p> 18 <p><input type="submit" value="提交"></p> 19 20 </form> 21 22 </body> 23 </html>
渲染
第一种渲染方式
form = UserForm()
注意:任何一个Field都有两个功能:验证和插件。
from django import forms # 引入forms组件
class UserForm(forms.Form): # 必须继承forms.Form
# forms.CharField和forms.EmailField会渲染为input标签
name = forms.CharField(min_length=4) # 默认label是字段名
pwd = forms.CharField(min_length=4, label="密码") # 如果需要中文label可以手动设置
r_pwd = forms.CharField(min_length=4, label="确认密码")
email = forms.EmailField(label="邮箱")
tel = forms.CharField(label="手机")
def reg(request):
form = UserForm()
return render(request, "reg.html", locals())
<h3>form组件渲染方式1</h3>
<form action="" method="post">
{% csrf_token %}
<p>{{ form.name.label }}
{{ form.name }}
</p>
<p>{{ form.pwd.label }}
{{ form.pwd }}
</p>
<p>{{ form.r_pwd.label }}
{{ form.r_pwd }}
</p>
<p>{{ form.email.label }}
{{ form.email }}
</p>
<p>{{ form.tel.label }}
{{ form.tel }}
</p>
<input type="submit">
</form>
第二种渲染方式
调用form对象的组件,即完成渲染。缺点是结构固定
{{ form.as_table }} 以表格的形式将它们渲染在<tr> 标签中
{{ form.as_p }} 将它们渲染在<p> 标签中
{{ form.as_ul }} 将它们渲染在<li> 标签中
<hr>
<h3>form组件渲染方式2</h3>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
</form>
初始化数据
在Web应用程序中开发编写功能时,时常用到获取数据库中的数据并将值初始化在HTML中的标签上。
if request.method =='GET':
values = { 'username': 'root', 'pwd': '123123', 'email': 'aaa@163.com', 'age':12, }
obj=FiForm(initial=values)
Form组件归类
全部字段
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 每一个Field都有一个正则表达式和默认插件 2 3 4 5 6 7 8 创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML; 9 10 Field 11 required=True, 是否允许为空 12 widget=None, HTML插件 13 label=None, 用于生成Label标签或显示内容 14 initial=None, 初始值 15 help_text='', 帮助信息(在标签旁边显示) 16 error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'} 17 show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直) 18 validators=[], 自定义验证规则 19 localize=False, 是否支持本地化 20 disabled=False, 是否可以编辑 21 label_suffix=None Label内容后缀 22 23 24 CharField(Field) 25 max_length=None, 最大长度 26 min_length=None, 最小长度 27 strip=True 是否移除用户输入空白 28 29 IntegerField(Field) 30 max_value=None, 最大值 31 min_value=None, 最小值 32 33 FloatField(IntegerField) 34 ... 35 36 DecimalField(IntegerField) 37 max_value=None, 最大值 38 min_value=None, 最小值 39 max_digits=None, 总长度 40 decimal_places=None, 小数位长度 41 42 BaseTemporalField(Field) 43 input_formats=None 时间格式化 44 45 DateField(BaseTemporalField) 格式:2015-09-01 46 TimeField(BaseTemporalField) 格式:11:12 47 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 48 49 DurationField(Field) 时间间隔:%d %H:%M:%S.%f 50 ... 51 52 RegexField(CharField) 53 regex, 自定制正则表达式 54 max_length=None, 最大长度 55 min_length=None, 最小长度 56 error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'} 57 58 EmailField(CharField) 59 ... 60 61 FileField(Field) 62 allow_empty_file=False 是否允许空文件 63 64 ImageField(FileField) 65 ... 66 注:需要PIL模块,pip3 install Pillow 67 以上两个字典使用时,需要注意两点: 68 - form表单中 enctype="multipart/form-data" 69 - view函数中 obj = MyForm(request.POST, request.FILES) 70 71 URLField(Field) 72 ... 73 74 75 BooleanField(Field) 76 ... 77 78 NullBooleanField(BooleanField) 79 ... 80 81 ChoiceField(Field) 82 ... 83 choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),) 84 required=True, 是否必填 85 widget=None, 插件,默认select插件 86 label=None, Label内容 87 initial=None, 初始值 88 help_text='', 帮助提示 89 90 91 ModelChoiceField(ChoiceField) 92 ... django.forms.models.ModelChoiceField 93 queryset, # 查询数据库中的数据 94 empty_label="---------", # 默认空显示内容 95 to_field_name=None, # HTML中value的值对应的字段 96 limit_choices_to=None # ModelForm中对queryset二次筛选 97 98 ModelMultipleChoiceField(ModelChoiceField) 99 ... django.forms.models.ModelMultipleChoiceField 100 101 102 103 TypedChoiceField(ChoiceField) 104 coerce = lambda val: val 对选中的值进行一次转换 105 empty_value= '' 空值的默认值 106 107 MultipleChoiceField(ChoiceField) 108 ... 109 110 TypedMultipleChoiceField(MultipleChoiceField) 111 coerce = lambda val: val 对选中的每一个值进行一次转换 112 empty_value= '' 空值的默认值 113 114 ComboField(Field) 115 fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式 116 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) 117 118 MultiValueField(Field) 119 PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用 120 121 SplitDateTimeField(MultiValueField) 122 input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] 123 input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] 124 125 FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中 126 path, 文件夹路径 127 match=None, 正则匹配 128 recursive=False, 递归下面的文件夹 129 allow_files=True, 允许文件 130 allow_folders=False, 允许文件夹 131 required=True, 132 widget=None, 133 label=None, 134 initial=None, 135 help_text='' 136 137 GenericIPAddressField 138 protocol='both', both,ipv4,ipv6支持的IP格式 139 unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用 140 141 SlugField(CharField) 数字,字母,下划线,减号(连字符) 142 ... 143 144 UUIDField(CharField) uuid类型 145 ...
补充:UUID
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> import uuid # make a UUID based on the host ID and current time >>> uuid.uuid1() # doctest: +SKIP UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') # make a UUID using an MD5 hash of a namespace UUID and a name >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') # make a random UUID >>> uuid.uuid4() # doctest: +SKIP UUID('16fd2706-8baf-433b-82eb-8c7fada847da') # make a UUID using a SHA-1 hash of a namespace UUID and a name >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d') # make a UUID from a string of hex digits (braces and hyphens ignored) >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}') # convert a UUID to a string of hex digits in standard form >>> str(x) '00010203-0405-0607-0809-0a0b0c0d0e0f' # get the raw 16 bytes of the UUID >>> x.bytes b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' # make a UUID from a 16-byte string >>> uuid.UUID(bytes=x.bytes) UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
全部插件
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 TextInput(Input) 2 NumberInput(TextInput) 3 EmailInput(TextInput) 4 URLInput(TextInput) 5 PasswordInput(TextInput) 6 HiddenInput(TextInput) 7 Textarea(Widget) 8 DateInput(DateTimeBaseInput) 9 DateTimeInput(DateTimeBaseInput) 10 TimeInput(DateTimeBaseInput) 11 CheckboxInput 12 Select 13 NullBooleanSelect 14 SelectMultiple 15 RadioSelect 16 CheckboxSelectMultiple 17 FileInput 18 ClearableFileInput 19 MultipleHiddenInput 20 SplitDateTimeWidget 21 SplitHiddenDateTimeWidget 22 SelectDateWidget
常用选择插件
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 # 单radio,值为字符串 2 # user = fields.CharField( 3 # initial=2, 4 # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) 5 # ) 6 7 # 单radio,值为字符串 8 # user = fields.ChoiceField( 9 # choices=((1, '上海'), (2, '北京'),), 10 # initial=2, 11 # widget=widgets.RadioSelect 12 # ) 13 14 # 单select,值为字符串 15 # user = fields.CharField( 16 # initial=2, 17 # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) 18 # ) 19 20 # 单select,值为字符串 21 # user = fields.ChoiceField( 22 # choices=((1, '上海'), (2, '北京'),), 23 # initial=2, 24 # widget=widgets.Select 25 # ) 26 27 # 多选select,值为列表 28 # user = fields.MultipleChoiceField( 29 # choices=((1,'上海'),(2,'北京'),), 30 # initial=[1,], 31 # widget=widgets.SelectMultiple 32 # ) 33 34 35 # 单checkbox 36 # user = fields.CharField( 37 # widget=widgets.CheckboxInput() 38 # ) 39 40 41 # 多选checkbox,值为列表 42 # user = fields.MultipleChoiceField( 43 # initial=[2, ], 44 # choices=((1, '上海'), (2, '北京'),), 45 # widget=widgets.CheckboxSelectMultiple 46 # )
补充:特殊的单选多选时,数据源如何实时更新
from django.forms import fields
from django.forms import widgets
from app01 import models
class Form(forms.Form):
user=fields.CharField()
passwd=fields.CharField(
widget=widgets.PasswordInput()
)
city_id=fields.IntegerField(
widget=widgets.Select()
)
#每次实例化类的时候都会执行,每次访问网页都会获取数据库里的最新信息
def __init__(self,*args,**kwargs):
super(Form,self).__init__(*args,**kwargs)
self.fields['city_id'].widget.choices=models.test.objects.values_list('id','city')