django中定义form表单的优势
- HTML中提交后,若数据出现错误,返回的页面中仍然可以保留之前输入的数据。
- 通过校验规则可以方便的限制字段条件并校验。
在Django中建个form表单
先要确定给什么表单构建。
使用form类
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(label='Your name', max_length=100)
#定义了一个form类,
字段最大长度max_length的定义,做了两件事,
1:在HTML的input上加了 maxlength="100"(浏览器会进行限制)
2:当Django收到浏览器发来的表单后,验证数据长度
渲染到HTML后:
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" maxlength="100">
注:不包含form标签和提交按钮,需要自己在HTML中写好。
is_valid
为所有字段进行验证,条件验证通过将:返回TRUE,将表单数据放到cleaned_data属性中。
视图
表单数据要通过视图处理,一般和发布的是同一个,可以重用相同逻辑。
from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import NameForm
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
#如果访问视图的是一个GET 请求,它将创建一个空的表单实例并将它放置到要渲染的模板的上下文中。
#如果表单的提交使用POST 请求,那么视图将再次创建一个表单实例并使用请求中的数据填充它:form = NameForm(request.POST)。这叫做”绑定数据至表单“(它现在是一个绑定的表单)。
#调用表单的is_valid()方法;如果它不为True,我们将带着这个表单返回到模板。这时表单不再为空(未绑定),所以HTML 表单将用之前提交的数据填充,然后可以根据要求编辑并改正它。
#如果is_valid()为True,我们将能够在cleaned_data 属性中找到所有合法的表单数据。在发送HTTP 重定向给浏览器告诉它下一步的去向之前,我们可以用这个数据来更新数据库或者做其它处理。
HTML模板
最简单的:
<form action="/your-name/" method="post">
{% csrf_token %}{{ form }}
<input type="submit" value="Submit" />
</form>
#{{ form }}即服务端对应的表单
注:Django 原生支持一个简单易用的跨站请求伪造的防护。当提交一个启用CSRF 防护的POST 表单时,你必须使用上面例子中的csrf_token 模板标签。
Django Form类
绑定的和未绑定的表单实例
- 未绑定的没有关联数据。渲染时为空或默认值
- 绑定的包含提交来的数据,可检验数据是否合法。若不合法,将包含内联的错误信息,返回。
字段详解
from django import forms
class RegForm(forms.Form):
u = forms.CharField(max_length=10
,error_messages={"max_length":"最长10字符","required":"字段不能为空"})
p = forms.CharField(mix_length=8,
widget=widgets.PasswordInput(attrs={"placeholder":"password"})
gender = forms.CharField(initial=2,
widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)))
email = forms.EmailField()
is_married = forms.BooleanField(required=False)
)
widgets
对应HTML表单的widget(type的数据类型格式)
不同字段默认不同widget,默认charfield是textinput widget。在HTML 中生成一个<input type="text">。
字段的数据
提交通过is_valid验证后,验证后的表单数据将存放于form.cleaned_data字典中(数据类型转换已好)
使用表单模板
若在字段属性中设置label,则会渲染成对于<label>/<input> 对。
表单渲染的选项
输出选项:
{{ form.as_table }} 以表格的形式将它们渲染在<tr> 标签中
{{ form.as_p }} 将它们渲染在<p> 标签中
{{ form.as_ul }} 将它们渲染在<li> 标签中
注意,若用table或ul。必须自己提供<table> 或<ul> 元素。
手动渲染
手工来做允许重新对字段排序。每个字段都是表单的一个属性。 使用{{ form.name_of_field }} 访问
<div class="fieldWrapper">
{{ form.Username.errors }}
{{ form.Username.label_tag }}
{{ form.Username }}
</div>
表单的错误信息及渲染
type(registerForm.errors)
#<class 'django.forms.utils.ErrorDict'> 错误清单,会渲染成ul
type(registerForm.errors["username"])
#<class 'django.forms.utils.ErrorList'>
form组件的钩子
即对接收到的form数据做自定义规则的判断。
定义Django的form时:
from django import forms class RegForm(forms.Form): username = forms.CharField(label='username', max_length=100) password = forms.CharField(label='password', max_length=100) repeat_password = forms.CharField(label='repeat_password',,max_length=100)
#钩子函数为对应字段添加判断条件。做最小长度判断 def clean_username(self): if len(self.cleaned_data.get("username"))>5: print(self.cleaned_data.get("password")) return self.cleaned_data.get("username") def clean_password(self): pass #全局钩子函数。判断两次密码输入是否一致 def clean(self): if self.cleaned_data["password"] == self.cleaned_data["repeat_password"]: return self.cleaned_data
———————————————————————————————————————————————————————————————————————————————————————
def foo(request): if request.method=="POST": regForm=RegForm(request.POST) if regForm.is_valid(): pass # 可用数据: regForm.cleaned_data, # 将数据插入数据库表中 else: pass # 可用数据: regForm.errors # 可以利用模板渲染讲errors嵌套到页面中返回 # 也可以打包到一个字典中,用于ajax返回 else: regForm=RegForm() return render(request,"register.html",{"regForm":regForm})
实例化时:
self.fields={
"username":"字段规则对象",
"password":"字段规则对象",
"
repeat_password":"字段规则对象",
}
is_valid时:
self._errors = {}
self.cleaned_data = {}
#局部钩子:
for name, field in self.fields.items():
try:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self.add_error(name, e)
# 全局钩子:
self.clean() # def self.clean():return self.cleaned_data
return not self.errors # True或者False
Filed字段通用配置参数如下
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类型 ...
widget的可配置字段插件(HTML中input的type值)
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
widget常用的选择插件
# 单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 # )