Django之Form组件(一)
Django的Form主要具有一下几大功能: 生成HTML标签
验证用户数据(显示错误信息)
HTML Form提交保留上次提交数据
初始化页面显示内容
基本操作:字段验证并显示错误信息,渲染标签(生成HTML标签),保留上次提交数据
from django.shortcuts import render,HttpResponse,redirect
from django import forms #引入模块
from django.forms import fields class FiForm(forms.Form): #必须继承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':'邮箱格式不对'
}) def login1(request): if request.method =='GET':
obj=FiForm()#第一次生成FiForm对象,没有传参,生成HTML代码
return render(request,"login1.html",{'obj':obj})
else:
u=request.POST.get('user') #不能为空,长度6-12
p=request.POST.get('passwd') #不能为空,长度12
e = request.POST.get('email')#不能为空,邮箱格式
a = request.POST.get('age')#不能为空,数字类型
print(u,p,e,a)
#检查是否为空
#检查格式
obj=FiForm(request.POST) #传入数据进行字段验证,form表单的name属性值应该与forms组件的字段名称一致,不一致的键值不会去做校验。
#是否全部验证成功,返回true或false
if obj.is_valid():
经过验证后得到的的数据
print('验证成功',obj.cleaned_data)
else:
print('验证失败',obj.errors) # 字段不符合要求的对应的键作为键,错误信息作为值 <ul class="errorlist"><li>r_pwd<ul class="errorlist">...
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login1/" method="POST">
{% csrf_token %}
<!--<p>用户名:<input type="text" name="user">{{ obj.errors.user.0 }}</p>-->
<!--<p>密码:<input type="password" name="passwd">{{ obj.errors.pwd.0 }}</p>-->
<!--<p>邮箱:<input type="text" name="email">{{ obj.errors.email.0 }}</p>-->
<!--<p>年龄:<input type="text" name="age">{{ obj.errors.age.0 }}</p>-->
<p>用户名:{{ obj.user }}{{ obj.errors.user.0 }}</p>
<p>密码:{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
<p>邮箱:{{ obj.email }}{{ obj.errors.email.0 }}</p>
<p>年龄:{{ obj.age }}{{ obj.errors.age.0 }}</p>
<p><input type="submit" value="提交"></p> </form> </body>
</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组件归类
全部字段
每一个Field都有一个正则表达式和默认插件 创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML; Field
required=True, 是否允许为空
widget=None, HTML插件
label=None, 用于生成Label标签或显示内容
initial=None, 初始值
help_text='', 帮助信息(在标签旁边显示)
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
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, 最小值 FloatField(IntegerField)
... DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 总长度
decimal_places=None, 小数位长度 BaseTemporalField(Field)
input_formats=None 时间格式化 DateField(BaseTemporalField) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 DurationField(Field) 时间间隔:%d %H:%M:%S.%f
... RegexField(CharField)
regex, 自定制正则表达式
max_length=None, 最大长度
min_length=None, 最小长度
error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'} EmailField(CharField)
... FileField(Field)
allow_empty_file=False 是否允许空文件 ImageField(FileField)
...
注:需要PIL模块,pip3 install Pillow
以上两个字典使用时,需要注意两点:
- form表单中 enctype="multipart/form-data"
- view函数中 obj = MyForm(request.POST, request.FILES) URLField(Field)
... BooleanField(Field)
... NullBooleanField(BooleanField)
... ChoiceField(Field)
...
choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默认select插件
label=None, Label内容
initial=None, 初始值
help_text='', 帮助提示 ModelChoiceField(ChoiceField)
... django.forms.models.ModelChoiceField
queryset, # 查询数据库中的数据
empty_label="---------", # 默认空显示内容
to_field_name=None, # HTML中value的值对应的字段
limit_choices_to=None # ModelForm中对queryset二次筛选 ModelMultipleChoiceField(ModelChoiceField)
... django.forms.models.ModelMultipleChoiceField TypedChoiceField(ChoiceField)
coerce = lambda val: val 对选中的值进行一次转换
empty_value= '' 空值的默认值 MultipleChoiceField(ChoiceField)
... TypedMultipleChoiceField(MultipleChoiceField)
coerce = lambda val: val 对选中的每一个值进行一次转换
empty_value= '' 空值的默认值 ComboField(Field)
fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式
fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) MultiValueField(Field)
PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用 SplitDateTimeField(MultiValueField)
input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
required=True,
widget=None,
label=None,
initial=None,
help_text='' GenericIPAddressField
protocol='both', both,ipv4,ipv6支持的IP格式
unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用 SlugField(CharField) 数字,字母,下划线,减号(连字符)
... UUIDField(CharField) uuid类型
...
补充:UUID
>>> 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')
全部插件
TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget
常用选择插件
# 单radio,值为字符串
# user = fields.CharField(
# initial=2,
# widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
# ) # 单radio,值为字符串
# user = fields.ChoiceField(
# choices=((1, '上海'), (2, '北京'),),
# initial=2,
# widget=widgets.RadioSelect
# ) # 单select,值为字符串
# user = fields.CharField(
# initial=2,
# widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
# ) # 单select,值为字符串
# user = fields.ChoiceField(
# choices=((1, '上海'), (2, '北京'),),
# initial=2,
# widget=widgets.Select
# ) # 多选select,值为列表
# user = fields.MultipleChoiceField(
# choices=((1,'上海'),(2,'北京'),),
# initial=[1,],
# widget=widgets.SelectMultiple
# ) # 单checkbox
# user = fields.CharField(
# widget=widgets.CheckboxInput()
# ) # 多选checkbox,值为列表
# user = fields.MultipleChoiceField(
# initial=[2, ],
# choices=((1, '上海'), (2, '北京'),),
# widget=widgets.CheckboxSelectMultiple
# )
补充:特殊的单选多选时,数据源如何实时更新
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')