Django中的form组件
Django中的form组件有两大作用
1、验证获取正确的结果或者错误信息
2、生成html代码
一、为什么需要form组件呢?
在写form表单,提交数据时,自己写验证的代码是一件非常困难的事情。

<form action="/test/"method="post">
{% csrf_token %}
<input type="text"name="user">
<input type="password"name="password">
<input type="email"name="email">
<input type="submit" value="提交">
</form>

上述表单提交后,在下面的视图中需要自己处理对提交数据的限制,非常的困难,而form组件能够实现对表单提交的数据进行验证的功能,也支持ajax提交的数据验证,错误是能获取错误信息。

def test(request):
if request.method =="GET":
return render(request,"test.html")
elif request.method == "POST":
user = request.POST.get("user")
password = request.POST.get("password")
email = request.POST.get("email")
print(user,password,email)
return HttpResponse("ok")

二、form组件的创建
先导入forms和fields,创建类和字段。字段中的参数和封装的正则表达式对传入进来的数据进行验证。将post传入进来的数据传入类中实例化生成一个对象,通过方法
is_valid(),可以拿到正确的数据或者错误的信息。

from django import forms
from django.forms import fields class MyForm(forms.Form):
user = fields.CharField(max_length=12,min_length=3,required=True)
password = fields.CharField(max_length=32,required=True)
email = fields.EmailField(required=True)


form_obj = MyForm(request.POST)
if form_obj.is_valid():
# 验证成功后拿到的数据
print(form_obj.cleaned_data)
else:
# 验证失败后,拿到的错误信息
print(form_obj.errors)

三、验证错误信息显示

<form action="/test/"method="post">
{% csrf_token %}
<p><input type="text"name="user">{{ form_obj.errors.user.0 }}</p>
<p><input type="password"name="password">{{ form_obj.errors.password.0 }}</p>
<p><input type="email"name="email">{{ form_obj.errors.email.0 }}</p>
<p><input type="submit" value="提交"></p>
</form>


class MyForm(forms.Form):
user = fields.CharField(max_length=12,min_length=3,required=True,error_messages={
"required":"用户不能为空",
"max_length":"用户名长度不能超过12个字符",
"min_length":"用户名长度不能短于3个字符",
})
password = fields.CharField(max_length=32,required=True,error_messages={
"max_length":"密码长度不能大于32个字符",
"required":"密码不能为空",
})
email = fields.EmailField(required=True,error_messages={
"required":"邮箱不能为空",
"invalid":"请输入邮箱格式",
})

error_message可以将错误信息定制为中文信息。
四、生成html代码
用form组件生成html代码有两个好处,1、当和其他人合作开发时,前端的form表单命名和后端form组件的字段名字不一样时,会出错,当采用form组件自动生成html代码不会存在名字不同的情况。2、可以保留上次输入的信息。

<form action="/test/"method="post">
{% csrf_token %}
<p>{{ form_obj.user }}{{ form_obj.errors.user.0 }}</p>
<p>{{ form_obj.password }}{{ form_obj.errors.password.0 }}</p>
<p>{{ form_obj.email }}{{ form_obj.errors.email.0 }}</p>
<p><input type="submit" value="提交"></p>
</form>


def test(request):
if request.method =="GET":
form_obj = MyForm()
return render(request,"test.html",locals())
elif request.method == "POST":
form_obj = MyForm(request.POST)
if form_obj.is_valid():
# 验证成功后拿到的数据
print(form_obj.cleaned_data)
else:
# 验证失败后,拿到的错误信息
print(form_obj.errors)
return render(request,"test.html",locals())
return HttpResponse("ok")

验证后通过form_obj.cleaned_data拿到的数据为字典,键为form中的字段名,因此当需要通过models.User.objects.create(**form_obj.cleaned_data)方法实现增加数据库中的数据时,需要足以保持model中和form中的字段名称相同。不同时,需要一个一个的传入字段。
五、整体结构
1、字段
字段的作用是提供验证时的格式要求,如果不符合格式要求则在error_message中的invalid定制错误信息。字段包含两样东西,验证的规则,生成html代码的wiget。
2、参数
参数实现对验证规则的正则表达式的定制。其中最重要的参数wiget实现对生成html代码的定制,可以生成不同的输入框(如select,Ridio,CheckBox),还能实现对生成的代码添加属性
3、一些常用实例
select,Ridio,CheckBox
ridio没有直接的字段,可以用其他的字段加上widget生成,一般经常选择的字段有CharField,ChoiceField,IntegerField
下面字段生成的html代码如下。

test = fields.ChoiceField(
required=True,
choices=((1,"重庆"),(2,"成都"),),
widget=widgets.RadioSelect()
)
test = fields.CharField(#用IntegerField一样
required=True,
widget=widgets.RadioSelect(choices=((1,"重庆"),(2,"成都"),),)
)


<ul id="id_test">
<li><label for="id_test_0"><input type="radio" name="test" value="1" required="" id="id_test_0">
重庆</label> </li>
<li><label for="id_test_1"><input type="radio" name="test" value="2" required="" id="id_test_1">
成都</label> </li>
</ul>

select
test = fields.IntegerField(
required=True,
widget=widgets.Select(choices=((1,"重庆"),(2,"成都"),),),
label="city"
)

test = fields.ChoiceField(
required=True,
choices=((1, "重庆"), (2, "成都"),),
widget=widgets.Select(),
label="city"
)

生成的html代码如下

<select name="test" id="id_test">
<option value="1">重庆</option> <option value="2">成都</option> </select>

select多

test = fields.ChoiceField(
required=True,
choices=((1, "重庆"), (2, "成都"),(3,"上海")),
widget=widgets.SelectMultiple(),
label="city"
)

产生的html代码如下:

<select name="test" required="" id="id_test" multiple="multiple">
<option value="1">重庆</option> <option value="2">成都</option> <option value="3">上海</option> </select>

checkbox单
test = fields.ChoiceField(
required=True,
widget=widgets.CheckboxInput(),
label="city"
)
<p>city<input type="checkbox" name="test" required="" id="id_test"></p>
checkbox多

test = fields.ChoiceField(
required=True,
choices=((1,"重庆"),(2,"成都"),(3,"上海")),
widget=widgets.CheckboxSelectMultiple(),
label="city"
)


<ul id="id_test">
<li><label for="id_test_0"><input type="checkbox" name="test" value="1" id="id_test_0">
重庆</label> </li>
<li><label for="id_test_1"><input type="checkbox" name="test" value="2" id="id_test_1">
成都</label> </li>
<li><label for="id_test_2"><input type="checkbox" name="test" value="3" id="id_test_2">
上海</label> </li>
</ul>

六、select选择数据库中的数据时,采用上面的创建类和字段的方法不能实现实时更新(即往数据库中添加数据,页面的下拉选择就能够出现更新的内容)
这是因为上述创建的字段为静态字段,在程序在载时加载后就不在执行了。可以采用如下的方式解决该问题。

test_user = fields.ChoiceField(
required=False,
choices=models.User.objects.values_list("id","user")
) def __init__(self,*args,**kwargs):
super(MyForm, self).__init__(*args,**kwargs)
self.fields["test_user"].widget.choices = models.User.objects.values_list("id","user")

将字段在初始化函数中再次赋值。
另外一种解决方法是:用ModelChoiceField字段
from django.forms.models import ModelChoiceField
test_user = ModelChoiceField(
queryset=models.User.objects.all(),
to_field_name="user"
) # to_field_name="user"指定生成option的html代码的value的值。
但是这个方法得到的下拉框中内容是一个对象,要是名字要用__str__方法。并且扩展性不强。
七、对数据的验证过程和验证扩展
对数据的验证是从is_valid开始,
def is_valid(self):
"""Return True if the form has no errors, or False otherwise."""
return self.is_bound and not self.errors

@property
def errors(self):
"""Return an ErrorDict for the data provided for the form."""
if self._errors is None:#没有错误时,继续验证,在full_clean中验证
self.full_clean()
return self._errors


def full_clean(self):
"""
Clean all of self.data and populate self._errors and self.cleaned_data.
"""
self._errors = ErrorDict()
if not self.is_bound: # Stop further processing.
return
self.cleaned_data = {}
# If the form is permitted to be empty, and none of the form data has
# changed from the initial data, short circuit any validation.
if self.empty_permitted and not self.has_changed():
return self._clean_fields()
self._clean_form()
self._post_clean()


def _clean_fields(self):
#name为字段名,field是具体的字段
for name, field in self.fields.items():
# value_from_datadict() gets the data from the data dictionaries.
# Each widget type knows how to retrieve its own data, because some
# widgets split data over several HTML fields.
if field.disabled:
value = self.get_initial_for_field(field, name)
else:
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, FileField):
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
#上述是进行正则表达式的验证,当正则表达式验证通过时,将值传递到self.cleaned_data中。下面是留的验证扩展的接口
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)

扩展时的类中函数名为clean_%s%name,函数要具有返回值;出错时,函数抛出ValidationError 异常。
如果存在较多的字段需要同时验证,在self._clean_form()中,

def _clean_form(self):
try:
cleaned_data = self.clean()#源代码中该函数没有执行任何操作,直接返回clean_data,因此源代码没有做任何处理
except ValidationError as e:
self.add_error(None, e)
else:
if cleaned_data is not None:
self.cleaned_data = cleaned_data


def clean(self):
"""
Hook for doing any extra form-wide cleaning after Field.clean() has been
called on every field. Any ValidationError raised by this method will
not be associated with a particular field; it will have a special-case
association with the field named '__all__'.
"""
return self.cleaned_data

在新建的类中,重写clean方法,可以实现对多个字段的验证,验证通过返回验证后的数据,出错时,抛出ValidationError 异常。捕捉到的异常加到错误信息中的键为__all__。

def _post_clean(self):
"""
An internal hook for performing additional cleaning after form cleaning
is complete. Used for model validation in model forms.
"""
pass

还有一个_post_clean()函数,什么也没做,可以自己写验证,但是用得较少,而且在源码中没有做任何的异常处理。
Django中的form组件的更多相关文章
- django中使用Form组件
内容: 1.Form组件介绍 2.Form组件常用字段 3.Form组件校验功能 4.Form组件内置正则校验 参考:https://www.cnblogs.com/liwenzhou/p/87478 ...
- Flask-wtforms类似django中的form组件
一.安装 pip3 install wtforms 二.简单使用 1.创建flask对象 from flask import Flask, render_template, request, redi ...
- Pyhon之Django中的Form组件
Pyhon之Django中的Form组件 新手上路 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面 ...
- python3-开发进阶Django-form组件中model form组件
Django的model form组件 这是一个神奇的组件,通过名字我们可以看出来,这个组件的功能就是把model和form组合起来,先来一个简单的例子来看一下这个东西怎么用:比如我们的数据库中有这样 ...
- Django框架 之 form组件的钩子
Django框架 之 form组件的钩子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 3 ...
- Django框架 之 form组件
Django框架 之 form组件 浏览目录 Form介绍 普通的登录 使用form组件 Form详情 常用字段 校验 进阶 使用Django Form流程 一.Form介绍 我们之前在HTML页面中 ...
- Django 的 model form 组件
Django 的 model form 组件 Model Form 组件的由来 之前介绍过 Django 的 Form 组件(Django的Form表单)使用方法,Form 组件能够帮我们做三件事: ...
- Django框架11 /form组件、modelForm组件
Django框架11 /form组件.modelForm组件 目录 Django框架11 /form组件.modelForm组件 1. form组件介绍 2. form常用字段与插件 3. form所 ...
- django中的forms组件
form介绍 用户需要向后端提交一些数据时,我们常常把这些数据放在一个form表单里,采用form标签,里面包含一些input等标签把用户的数据提交给后端. 在给后端提交数据的时候,我们常常也需要对于 ...
随机推荐
- 3D Slicer中文教程(三)—数据加载及保存方式
1.打开数据与保存数据 (1)打开数据 ——可以将数据拖拽到3D Slicer应用窗口或者从菜单栏工具栏打开. ——多种方式加载大量数据. 有关DICOM数据,请参阅DICOM模块文档. 对于几乎所有 ...
- python正则表达式--特殊字符
正则表达式—特殊表达式含义 正则表达式的字母和数字表示他们自身,但多数字母和数字前加一个反斜杠时会拥有不同的含义. 下面列出了正则表达式模式语法中的特殊元素. 1.普通字符集 1) \w ...
- 《剑指offer》二叉搜索树和双向链表
本题来自<剑指offer> 反转链表 题目: 思路: C++ Code: Python Code: 总结:
- hexo基本操作
1.新建一篇文章:hexo new post "article title" 2.生成静态网页:hexo g 3.预览效果:hexo s 4.发布:hexo d
- Mysql的性能优化
1.参考书籍:MYSQL 5.5从零开始学 Mysql性能优化就算通过合理安排资源,调整系统参数使MYSQL运行更快,更节省资源.MYSQL性能优化包括查询速度优化,更新速度优化,mysql服务器优化 ...
- left join on and 与 left join on where的区别
数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户. 在使用left jion时,on和where条件的区别如下: 1. on条件是在生成临时 ...
- 设计模式学习之访问者模式(Visitor,行为型模式)(21)
参考:https://www.cnblogs.com/edisonchou/p/7247990.html 在患者就医时,医生会根据病情开具处方单,很多医院都会存在以下这个流程:划价人员拿到处方单之后根 ...
- python运算符——比较运算符
比较运算符的运算结果会得到一个bool类型,也就是逻辑判定,要么是真True,要不就是False 大于“>” 小于“<” 不说了,看看不等于,用“!=”表示.大于等于“>=”和小 ...
- Promise源码深入理解
) ) }); ) }, ) }); ) ) }, ) }); ) }, ) }); p.then(function (x) { console.log(x) }) //输出 1 链式调用1 链式调用 ...
- redis初步入门(1)
一.redis是一款高性能NOSQL系列的非关系型的数据库,其是用C语言开发的一个开源高性能键值对(key-value)数据库. 二.redis的应用场景 1.缓存(数据查询.短连接.新闻内容.商品内 ...