django-Form组件
程序员文章站
2022-04-25 15:18:09
...
Widgets
每个表单字段都有一个对应的Widget 类,它对应一个HTML 表单Widget,例如。
在大部分情况下,字段都具有一个合理的默认Widget。例如,默认情况下,CharField 具有一个TextInput Widget,它在HTML 中生成一个。
表单渲染
对于
{{ form.as_table }} 以表格的形式将它们渲染在<tr> 标签中
{{ form.as_p }} 将它们渲染在<p> 标签中
{{ form.as_ul }} 将它们渲染在<li> 标签中
注意,你必须自己提供
或- 元素。
{{ form.as_p }}会渲染如下:
Django内置字段
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类型
...
Django内置插件
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
# )
实例代码
views.py
from django.shortcuts import render, redirect, HttpResponse
from django import forms
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
from django.forms import widgets
from app07 import models
class RegistForm(forms.Form):
user = forms.CharField(max_length=18, min_length=3,
error_messages={
'required': '不能为空',
'min_length': 'too short',
'max_length': "too long"
})
pwd = forms.CharField(max_length=32, min_length=3,
error_messages={
'max_length': "too long",
'required': '不能为空',
'min_length': 'too short',
},
widget=widgets.PasswordInput(attrs={"class":"active"}))
rePwd = forms.CharField(label='确认密码',
max_length=32,
error_messages={},
widget=widgets.PasswordInput(attrs={"class":"active"}))
email = forms.EmailField(
error_messages={
"invalid": '格式错误'
}
)
phone =forms.CharField()
def clean_user(self):
val = self.cleaned_data.get("user")
ret = models.User.objects.filter(name=val)
if not ret:
return val
else:
raise ValidationError("该用户已经注册")
def clean_phone(self):
val = self.cleaned_data.get('phone')
import re
ret = re.search("1[356789]\d{9}$", val)
if ret:
return val
else:
raise ValidationError("手机号格式错误")
def clean(self):
pwd = self.cleaned_data.get('pwd')
repeat_pwd = self.cleaned_data.get('rePwd')
if pwd == repeat_pwd:
return self.cleaned_data
else:
raise ValidationError("两次密码不一致")
def regist(request):
if request.method == "POST":
registForm = RegistForm(request.POST)
# 全部校验无误
if registForm.is_valid():
print("is_valid cleaned_data-------",registForm.cleaned_data)
user = registForm.cleaned_data.get("user")
pwd = registForm.cleaned_data.get("pwd")
models.User.objects.create(name=user,pwd=pwd)
return HttpResponse("ok")
else:
# 最少存在一个字段错误
print("errors-------",registForm.errors) # {"字段":["","",""]}
# print("errors-------",registForm.errors["pwd"]) # {"pwd":""}
print("is_not_valid clean_data",registForm.cleaned_data) #{'user': 'safly'}
print(registForm.errors.get("__all__"))
return render(request,"regist.html",{"registForm": registForm})
registForm = RegistForm()
return render(request, "regist.html", {"registForm": registForm})
regist.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<style>
.active{
border: 1px solid crimson;
}
.err_span{
color: red;
}
</style>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
{{ registForm.as_p }}
<input type="submit" value="提交">
</form>
<hr>
<form action="/regist/" method="post" novalidate>
{% csrf_token %}
<div>
<label for="">输入姓名:</label> {{ registForm.user }}
<span class="err_span">{{ registForm.errors.user.0 }}</span>
</div>
<div>
<label for="">输入密码:</label> {{ registForm.pwd }}
<span class="err_span">{{ registForm.errors.pwd.0 }}</span>
</div>
<div>
<label for="">{{ registForm.rePwd.label }}</label> {{ registForm.rePwd }}
<span class="err_span">{{ registForm.non_field_errors.0}}</span>
</div>
<div>
<label for="">输入邮箱:</label> {{ registForm.email }}
<span class="err_span">{{ registForm.errors.email.0 }}</span>
</div>
<div>
<label for="">输入电话:</label> {{ registForm.phone }}
<span class="err_span">{{ registForm.errors.phone.0 }}</span>
</div>
<input type="submit" value="提交">
</form>
</body>
</html>
如果校验全队输出如下:
is_valid cleaned_data------- {'user': 'dfdsfsdf', 'pwd': 'rrrr', 'rePwd': 'rrrr', 'email': 'aaa@qq.com', 'phone': '13545678908'}
如果我们按着如下的校验:
局部钩子只校验 用户名、手机
全局钩子只校验密码
如果我们邮箱输错、电话输错,密码输错,看下最后输出是什么?
errors------- <ul class="errorlist"><li>phone<ul class="errorlist"><li>手机号格式错误</li></ul></li><li>__all__<ul class="errorlist nonfield"><li>两次密码不一致</li></ul></li></ul>
is_not_valid clean_data {'user': '梵蒂冈', 'pwd': 'rrrr', 'rePwd': 'fdsf', 'email': 'aaa@qq.com'}
<ul class="errorlist nonfield"><li>两次密码不一致</li></ul>
errors里面只是密码框、手机号框输出,因为局部钩子没有校验邮箱
clean_data 用户名、密码、确认密码、邮箱
以下是伪代码,我们forms组件渲染有3种方式,我们还可以利用如下的方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<style>
span {
color: red;
}
</style>
</head>
<body>
<h3>注册页面</h3>
<form action="" novalidate method="post">
{% csrf_token %}
{% for field in reg_form %}
<div>
<label for="">{{ field.label }}</label>
{{ field }}<span>{{ field.errors.0 }}</span>
{% if field.label == '确认密码' %}
<span>{{ all_error.0 }}</span>
{% endif %}
</div>
{% endfor %}
<input type="submit">
</form>
</body>
<html>
上一篇: Django学习--form(表单)
下一篇: Django之form组件