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字段通用配置参数如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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内容后缀
不同字段的配置参数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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值)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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常用的选择插件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# 单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 # )