Form组件介绍
在HTML页面中form表单会把用户输入标签的数据包起来提交后端。大多数情况下需要对用户输入的数据做校验(比如长度和格式),如果数据有错误就需要在页面上输出相应的错误信息。
Django的Form组件就会很方便的校验,同时保留上次用户输入内容
HTML和Django的Form区别
HTML上Form
register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
</head>
<body>
<form action="/register/" method="post">
{% csrf_token %}
<p>
用户名:
<input type="text" name="username">
<span style="color: red">{{ arg_error.username }}</span>
</p>
<p>
密 码:
<input type="password" name="pwd">
<span style="color: red">{{ arg_error.pwd }}</span>
</p>
<p>
<input type="submit" value="提交">
</p>
</form>
</body>
</html>
Django项目中views.py
## 注册页面信息提交的函数
def register(request):
## 定义返回错误信息
arg_error = {"username": "", "pwd": ""}
if request.method == "POST":
## 获取用户输入的数据到变量
username = request.POST.get("username", None)
pwd = request.POST.get("pwd", None)
## 校验
if username:
arg_error["username"] = "用户名不能为空!"
if pwd:
arg_error["pwd"] = "密码不能为空!"
elif len(pwd) < 6:
arg_error["pwd"] = "密码不能小于6位!"
else:
## 把数据保存到数据库中
models.UserInfo.objects.create(user=username, pwd=pwd)
## 返回用户信息
return HttpResponse("注册成功!")
return render(request, "arg.html", {'arg_error': arg_error})
Django上Form
Django项目中views.py
定义Form类
## 导入Form组件和widget渲染页面
from django import forms
from django.forms import widgets
## 定义类,继承Form类
class Argforms(forms.Form):
## 定义类变量(max_length最大值、label页面显示标签、error_messages返回的错误信息)
username = forms.CharField(max_length=16, label="用户名", error_messages={
"required": "用户名不能为空!",
})
## widget定义页面input标签type为password
pwd = forms.CharField(min_length=6, label="密码", error_messages={
"min_length": "密码不能小于6位!",
"required": "密码不能为空",
},widget = widgets.PasswordInput)
注册页面信息提交的函数
def register2(request):
## 上面定义的类赋值到变量
in_form = Argforms()
## 校验
if request.method == "POST":
in_form = Argforms(request.POST)
## 判断校验是否通过
if in_form.is_valid():
## 把数据保存到数据库中
models.UserInfo.objects.create(**in_form.cleaned_data)
## 返回用户信息
return HttpResponse("注册成功!")
return render(request, 'register2.html', {'in_form': in_form})
register2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>页面注册</title>
</head>
<body>
<form action="/register2/" method="post" novalidate>
{% csrf_token %}
<p>
{{ in_form.username.label }}
{{ in_form.username }}
<span style="color: red">{{ in_form.username.errors.0 }}</span>
</p>
<p>
{{ in_form.pwd.label }}
{{ in_form.pwd }}
<span style="color: red"> {{ in_form.pwd.errors.0 }}</span>
</p>
<p>
{{ in_form.re_pwd.label }}
{{ in_form.re_pwd }}
<span style="color: red">{{ in_form.re_pwd.errors.0 }}</span>
</p>
<p>
<input type="submit" value="提交">
</p>
</form>
</body>
</html>
Form组件其他输入标签
邮箱
class Argforms(forms.Form):
···
Email = forms.EmailField()
单选Select
class Argforms(forms.Form):
···
city = forms.ChoiceField(
label="所在城市",
## 所有选项
choices=((1, '北京'), (2, '上海'), (3, '广州')),
## 默认选中
initial=1,
)
多选Select
class Argforms(forms.Form):
···
gender = forms.MultipleChoiceField(
label="爱好",
choices=((1, '篮球'), (2, '足球'), (3, '台球'), (4, '保龄球')),
initial=[1, 3],
单选Checkbox
class Argforms(forms.Form):
···
gender = forms.ChoiceField(
label="性别",
choices=((1, '男'), (2, '女'), (3, '保密')),
initial=3,
widget= forms.widgets.RadioSelect
)
多选Checkbox
class Argforms(forms.Form):
···
gender = forms.MultipleChoiceField(
label="爱好",
choices=((1, '篮球'), (2, '足球'), (3, '台球'), (4, '保龄球')),
initial=[1, 3],
widget= forms.widgets.CheckboxSelectMultiple
给标签定义类,方便页面上的css、js对标签进行处理
class Argforms(forms.Form):
username = forms.CharField(max_length=16, label="用户名", error_messages={
"required": "用户名不能为空!",
}, ## attrs设置属性,定义class为p1
widget= forms.widgets.TextInput(attrs={'class': 'p1'}))
校验
Form组件中除了内置的校验(min_length最小值/max_length最大值/required是否为空)外,还是如下:
- 使用正则校验
- 自定义校验函数
- 使用Form类中内置的
clean_字段名()
方法进行字段校验 - 使用Form类中内置的
clean()
方法进行全局校验
正则校验
## 导入内置的正则
from django.core.validators import RegexValidator
class Argforms(forms.Form):
···
phone = forms.CharField(
label="手机",
## 自定义规则
validators=[
## 使用正则匹配,匹配不上返回后面的错误信息
RegexValidator(r'[0-9]+$', "手机号必须是数字!"),
RegexValidator(r'^1[3-9][0-9]{9}$', "手机号格式不对!")
]
),
自定义校验函数
## 导入Python的正则模块
import re
## 导入Django错误格式
from django.core.exceptions import ValidationError
## 定义校验规则
def PhoneCheck(value):
check = re.compile(r'^1[3-9][0-9]{9}$')
if not check.match(value):
raise ValidationError('手机号格式错误!')
class Argforms(forms.Form):
···
phone = forms.CharField(
label="手机",
## 引用自定义函数校验
validators=[PhoneCheck, ],
)
clean_字段名() 字段校验
## 导入Django错误格式
from django.core.exceptions import ValidationError
class Argforms(forms.Form):
username = forms.CharField(max_length=16, label="用户名", error_messages={
"required": "用户名不能为空!",
},)
## 定义方法,用来校验username字段
def clean_username(self):
value = self.cleaned_data.get("username", None)
if value in "***":
raise ValidationError("禁止吐星星!")
else:
return value
clean() 进行全局校验
class Argforms(forms.Form):
···
pwd = forms.CharField(min_length=6, label="密码", error_messages={
"min_length": "密码不能小于6位!",
"required": "密码不能为空",
}, widget = widgets.PasswordInput)
re_pwd = forms.CharField(min_length=6, label="确认密码", error_messages={
"min_length": "密码不能小于6位!",
"required": "密码不能为空",
}, widget = widgets.PasswordInput)
## 定义方法,用来校验密码和确认密码是否一致
def clean(self):
pwd = self.cleaned_data.get("pwd", None)
re_pwd = self.cleaned_data.get("re_pwd", None)
if pwd != re_pwd:
self.add_error("re_pwd", "两次密码不一致!")
else:
return self.cleaned_data
Field
required=True —— —— —— 是否允许为空
widget=None —— —— —— HTML插件
label=None —— —— —— 用于生成Label标签或显示内容
initial=None —— —— —— 初始值
help_text='' —— —— —— 帮助信息(在标签旁边显示)
error_messages=None —— —— —— 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
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类型