- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章在Python的Flask中使用WTForms表单框架的基础教程由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
下载和安装 安装 WTForms 最简单的方式是使用 easy_install 和 pip
1
2
3
|
easy_install WTForms
# or
pip
install
WTForms
|
你可以从 PyPI 手动 下载 WTForms 然后运行 python setup.py install . 。
如果你是那种喜欢这一切风险的人, 就运行来自 Git 的最新版本, 你能够获取最新变更集的 打包版本, 或者前往 项目主页 克隆代码仓库. 。
主要概念 Forms 类是 WTForms 的核心容器. 表单(Forms)表示域(Fields)的集合, 域能通过表单的字典形式或者属性形式访问. Fields(域)做最繁重的工作. 每个域(field)代表一个数据类型, 并且域操作强制表单输入为那个数据类型. 例如, InputRequired 和 StringField 表示两种不同的数据类型. 域除了包含的数据(data)之外, 还包含大量有用的属性, 例如标签、描述、验证错误的列表. 每个域(field)拥有一个Widget(部件)实例. Widget 的工作是渲染域(field)的HTML表示. 每个域可以指定Widget实例, 但每个域默认拥有一个合理的widget. 有些域是简单方便的, 比如 TextAreaField 就仅仅是默认部件(widget) 为 TextArea 的 StringField. 为了指定验证规则, 域包含验证器(Validators)列表. 开始 让我们直接进入正题并定义我们的第一个表单:
1
2
3
4
5
6
|
from
wtforms
import
Form, BooleanField, StringField, validators
class
RegistrationForm(Form):
username
=
StringField(
'Username'
, [validators.Length(
min
=
4
,
max
=
25
)])
email
=
StringField(
'Email Address'
, [validators.Length(
min
=
6
,
max
=
35
)])
accept_rules
=
BooleanField(
'I accept the site rules'
, [validators.InputRequired()])
|
当你创建一个表单(form), 你定义域(field)的方法类似于很多ORM定义它们的列(columns):通过定义类变量, 即域的实例. 。
因为表单是常规的 Python 类, 你可以很容易地把它们扩展成为你期望的:
1
2
3
4
5
6
7
|
class
ProfileForm(Form):
birthday
=
DateTimeField(
'Your Birthday'
,
format
=
'%m/%d/%y'
)
signature
=
TextAreaField(
'Forum Signature'
)
class
AdminProfileForm(ProfileForm):
username
=
StringField(
'Username'
, [validators.Length(
max
=
40
)])
level
=
IntegerField(
'User Level'
, [validators.NumberRange(
min
=
0
,
max
=
10
)])
|
通过子类, AdminProfileForm 类获得了已经定义的 ProfileForm 类的所有域. 这允许你轻易地在不同表单之间共享域的共同子集, 例如上面的例子, 我们增加 admin-only 的域到 ProfileForm. 。
使用表单 使用表单和实例化它一样简单. 想想下面这个django风格的视图函数, 它使用之前定义的 RegistrationForm 类:
1
2
3
4
5
6
7
8
9
|
def
register(request):
form
=
RegistrationForm(request.POST)
if
request.method
=
=
'POST'
and
form.validate():
user
=
User()
user.username
=
form.username.data
user.email
=
form.email.data
user.save()
redirect(
'register'
)
return
render_response(
'register.html'
, form
=
form)
|
首先, 我们实例化表单, 给它提供一些 request.POST 中可用的数据. 然后我们检查请求(request)是不是使用 POST 方式, 如果它是, 我们就验证表单, 并检查用户遵守这些规则. 如果成功了, 我们创建新的 User 模型, 并从已验证的表单分派数据给它, 最后保存它. 。
编辑现存对象 。
我们之前的注册例子展示了如何为新条目接收输入并验证, 只是如果我们想要编辑现有对象怎么办?很简单:
1
2
3
4
5
6
7
8
|
def
edit_profile(request):
user
=
request.current_user
form
=
ProfileForm(request.POST, user)
if
request.method
=
=
'POST'
and
form.validate():
form.populate_obj(user)
user.save()
redirect(
'edit_profile'
)
return
render_response(
'edit_profile.html'
, form
=
form)
|
这里, 我们通过给表单同时提供 request.POST 和用户(user)对象来实例化表单. 通过这样做, 表单会从 user 对象得到在未在提交数据中出现的任何数据. 。
我们也使用表单的populate_obj方法来重新填充用户对象, 用已验证表单的内容. 这个方法提供便利, 用于当域(field)名称和你提供数据的对象的名称匹配时. 通常的, 你会想要手动分配值, 但对于这个简单例子, 它是最好的. 它也可以用于CURD和管理(admin)表单. 。
在控制台中探索 。
WTForms 表单是非常简单的容器对象, 也许找出表单中什么对你有用的最简单的方法就是在控制台中玩弄表单
1
2
3
4
5
6
7
8
9
10
11
12
13
|
>>>
from
wtforms
import
Form, StringField, validators
>>>
class
UsernameForm(Form):
... username
=
StringField(
'Username'
, [validators.Length(
min
=
5
)], default
=
u
'test'
)
...
>>> form
=
UsernameForm()
>>> form[
'username'
]
<wtforms.fields.StringField
object
at
0x827eccc
>
>>> form.username.data
u
'test'
>>> form.validate()
False
>>> form.errors
{
'username'
: [u
'Field must be at least 5 characters long.'
]}
|
我们看到的是当你实例化一个表单的时候, 表单包含所有域的实例, 访问域可以通过字典形式或者属性形式. 这些域拥有它们自己的属性, 就和封闭的表单一样. 。
当我们验证表单, 它返回逻辑假, 意味着至少一个验证规则不满足. form.errors 会给你一个所有错误的概要. 。
1
2
3
4
5
|
>>> form2
=
UsernameForm(username
=
u
'Robert'
)
>>> form2.data
{
'username'
: u
'Robert'
}
>>> form2.validate()
True
|
这次, 我们实例化 UserForm 时给 username 传送一个新值, 验证表单是足够了. 。
表单如何获取数据 除了使用前两个参数(formdata和obj)提供数据之外, 你可以传送关键词参数来填充表单. 请注意一些参数名是被保留的: formdata, obj, prefix. 。
formdata比obj优先级高, obj比关键词参数优先级高. 例如
1
2
3
4
5
6
7
8
|
def
change_username(request):
user
=
request.current_user
form
=
ChangeUsernameForm(request.POST, user, username
=
'silly'
)
if
request.method
=
=
'POST'
and
form.validate():
user.username
=
form.username.data
user.save()
return
redirect(
'change_username'
)
return
render_response(
'change_username.html'
, form
=
form)
|
虽然你在实践中几乎从未一起使用所有3种方式, 举例说明WTForms是如何查找 username 域
如果表单被提交(request.POST非空), 则处理表单输入. 实践中, 即使这个域没有 表单输入, 而如果存在任何种类的表单输入, 那么我们会处理表单输入. 如果没有表单输入, 则按下面的顺序尝试
验证器 。
WTForms中的验证器(Validators)为域(field)提供一套验证器, 当包含域的表单进行验证时运行. 你提供验证器可通过域构造函数的第二个参数validators
1
2
|
class
ChangeEmailForm(Form):
email
=
StringField(
'Email'
, [validators.Length(
min
=
6
,
max
=
120
), validators.Email()])
|
你可以为一个域提供任意数量的验证器. 通常, 你会想要提供一个定制的错误消息
1
2
3
4
5
|
class
ChangeEmailForm(Form):
email
=
StringField(
'Email'
, [
validators.Length(
min
=
6
, message
=
_(u
'Little short for an email address?'
)),
validators.Email(message
=
_(u
'That\'s not a valid email address.'
))
])
|
这通常更好地提供你自己的消息, 作为必要的默认消息是通用的. 这也是提供本地化错误消息的方法. 。
对于内置的验证器的列表, 查阅 Validators. 。
渲染域 渲染域和强制它为字符串一样简单
1
2
3
4
5
6
7
8
9
|
>>>
from
wtforms
import
Form, StringField
>>>
class
SimpleForm(Form):
... content
=
StringField(
'content'
)
...
>>> form
=
SimpleForm(content
=
'foobar'
)
>>>
str
(form.content)
'<input id="content" name="content" type="text" value="foobar" />'
>>>
unicode
(form.content)
u
'<input id="content" name="content" type="text" value="foobar" />'
|
然而, 渲染域的真正力量来自于它的 __call__() 方法. 调用(calling)域, 你可以提供关键词参数, 它们会在输出中作为HTML属性注入. 。
1
2
|
>>> form.content(style
=
"width: 200px;"
,
class_
=
"bar"
)
u
'<input class="bar" id="content" name="content" style="width: 200px;" type="text" value="foobar" />'
|
现在, 让我们应用这个力量在 Jinja 模板中渲染表单. 首先, 我们的表单
1
2
3
4
5
|
class
LoginForm(Form):
username
=
StringField(
'Username'
)
password
=
PasswordField(
'Password'
)
form
=
LoginForm()
|
然后是模板文件
1
2
3
4
|
<form method
=
"POST"
action
=
"/login"
>
<div>{{ form.username.label }}: {{ form.username(
class
=
"css_class"
) }}<
/
div>
<div>{{ form.password.label }}: {{ form.password() }}<
/
div>
<
/
form>
|
相同的, 如果你使用 Django 模板, 当你想要传送关键词参数时, 你可以使用我们在Django扩展中提供的模板标签form_field
1
2
3
4
5
6
7
8
9
10
11
|
{
%
load wtforms
%
}
<form method
=
"POST"
action
=
"/login"
>
<div>
{{ form.username.label }}:
{
%
form_field form.username
class
=
"css_class"
%
}
<
/
div>
<div>
{{ form.password.label }}:
{{ form.password }}
<
/
div>
<
/
form>
|
这两个将会输出
1
2
3
4
5
6
7
8
9
10
|
<form method
=
"POST"
action
=
"/login"
>
<div>
<label
for
=
"username"
>Username<
/
label>:
<
input
class
=
"css_class"
id
=
"username"
name
=
"username"
type
=
"text"
value
=
""
/
>
<
/
div>
<div>
<label
for
=
"password"
>Password<
/
label>:
<
input
id
=
"password"
name
=
"password"
type
=
"password"
value
=
""
/
>
<
/
div>
<
/
form>
|
WTForms是模板引擎不可知的, 同时会和任何允许属性存取、字符串强制(string coercion)、函数调用的引擎共事. 在 Django 模板中, 当你不能传送参数时, 模板标签 form_field 提供便利. 。
显示错误消息 现在我们的表单拥有一个模板, 让我们增加错误消息:
1
2
3
4
5
6
7
8
9
10
11
|
<form method
=
"POST"
action
=
"/login"
>
<div>{{ form.username.label }}: {{ form.username(
class
=
"css_class"
) }}<
/
div>
{
%
if
form.username.errors
%
}
<ul
class
=
"errors"
>{
%
for
error
in
form.username.errors
%
}<li>{{ error }}<
/
li>{
%
endfor
%
}<
/
ul>
{
%
endif
%
}
<div>{{ form.password.label }}: {{ form.password() }}<
/
div>
{
%
if
form.password.errors
%
}
<ul
class
=
"errors"
>{
%
for
error
in
form.password.errors
%
}<li>{{ error }}<
/
li>{
%
endfor
%
}<
/
ul>
{
%
endif
%
}
<
/
form>
|
如果你喜欢在顶部显示大串的错误消息, 也很简单
1
2
3
4
5
6
7
8
9
|
{
%
if
form.errors
%
}
<ul
class
=
"errors"
>
{
%
for
field_name, field_errors
in
form.errors|dictsort
if
field_errors
%
}
{
%
for
error
in
field_errors
%
}
<li>{{ form[field_name].label }}: {{ error }}<
/
li>
{
%
endfor
%
}
{
%
endfor
%
}
<
/
ul>
{
%
endif
%
}
|
由于错误处理会变成相当冗长的事情, 在你的模板中使用 Jinja 宏(macros, 或者相同意义的) 来减少引用是更好的. (例子) 。
定制验证器 这有两种方式定制的验证器. 通过定义一个定制的验证器并在域中使用它
1
2
3
4
5
6
7
8
|
from
wtforms.validators
import
ValidationError
def
is_42(form, field):
if
field.data !
=
42
:
raise
ValidationError(
'Must be 42'
)
class
FourtyTwoForm(Form):
num
=
IntegerField(
'Number'
, [is_42])
|
或者通过提供一个在表单内的特定域(in-form field-specific)的验证器
1
2
3
4
5
6
|
class
FourtyTwoForm(Form):
num
=
IntegerField(
'Number'
)
def
validate_num(form, field):
if
field.data !
=
42
:
raise
ValidationError(u
'Must be 42'
)
|
编写WTForm扩展示例 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class
TagListField(Field):
widget
=
TextInput()
def
_value(
self
):
if
self
.data:
return
u
', '
.join(
self
.data)
else
:
return
u''
def
process_formdata(
self
, valuelist):
if
valuelist:
self
.data
=
[x.strip()
for
x
in
valuelist[
0
].split(
','
)]
else
:
self
.data
=
[]
|
根据上面的代码,将TagListField中的字符串转为models.py中定义的Tag对象即可:
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
class
TagListField(Field):
widget
=
TextInput()
def
__init__(
self
, label
=
None
, validators
=
None
,
*
*
kwargs):
super
(TagListField,
self
).__init__(label, validators,
*
*
kwargs)
def
_value(
self
):
if
self
.data:
r
=
u''
for
obj
in
self
.data:
r
+
=
self
.obj_to_str(obj)
return
u''
else
:
return
u''
def
process_formdata(
self
, valuelist):
print
'process_formdata..'
print
valuelist
if
valuelist:
tags
=
self
._remove_duplicates([x.strip()
for
x
in
valuelist[
0
].split(
','
)])
self
.data
=
[
self
.str_to_obj(tag)
for
tag
in
tags]
else
:
self
.data
=
None
def
pre_validate(
self
, form):
pass
@classmethod
def
_remove_duplicates(
cls
, seq):
"""去重"""
d
=
{}
for
item
in
seq:
if
item.lower()
not
in
d:
d[item.lower()]
=
True
yield
item
@classmethod
def
str_to_obj(
cls
, tag):
"""将字符串转换位obj对象"""
tag_obj
=
Tag.query.filter_by(name
=
tag).first()
if
tag_obj
is
None
:
tag_obj
=
Tag(name
=
tag)
return
tag_obj
@classmethod
def
obj_to_str(
cls
, obj):
"""将对象转换为字符串"""
if
obj:
return
obj.name
else
:
return
u''
class
TagListField(Field):
widget
=
TextInput()
def
__init__(
self
, label
=
None
, validators
=
None
,
*
*
kwargs):
super
(TagListField,
self
).__init__(label, validators,
*
*
kwargs)
def
_value(
self
):
if
self
.data:
r
=
u''
for
obj
in
self
.data:
r
+
=
self
.obj_to_str(obj)
return
u''
else
:
return
u''
def
process_formdata(
self
, valuelist):
print
'process_formdata..'
print
valuelist
if
valuelist:
tags
=
self
._remove_duplicates([x.strip()
for
x
in
valuelist[
0
].split(
','
)])
self
.data
=
[
self
.str_to_obj(tag)
for
tag
in
tags]
else
:
self
.data
=
None
def
pre_validate(
self
, form):
pass
@classmethod
def
_remove_duplicates(
cls
, seq):
"""去重"""
d
=
{}
for
item
in
seq:
if
item.lower()
not
in
d:
d[item.lower()]
=
True
yield
item
@classmethod
def
str_to_obj(
cls
, tag):
"""将字符串转换位obj对象"""
tag_obj
=
Tag.query.filter_by(name
=
tag).first()
if
tag_obj
is
None
:
tag_obj
=
Tag(name
=
tag)
return
tag_obj
@classmethod
def
obj_to_str(
cls
, obj):
"""将对象转换为字符串"""
if
obj:
return
obj.name
else
:
return
u''
|
主要就是在process_formdata这一步处理表单的数据,将字符串转换为需要的数据。最终就可以在forms.py中这样定义表单了:
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
...
class
ArticleForm(Form):
"""编辑文章表单"""
title
=
StringField(u
'标题'
, validators
=
[Required()])
category
=
QuerySelectField(u
'分类'
, query_factory
=
get_category_factory([
'id'
,
'name'
]), get_label
=
'name'
)
tags
=
TagListField(u
'标签'
, validators
=
[Required()])
content
=
PageDownField(u
'正文'
, validators
=
[Required()])
submit
=
SubmitField(u
'发布'
)
...
...
class
ArticleForm(Form):
"""编辑文章表单"""
title
=
StringField(u
'标题'
, validators
=
[Required()])
category
=
QuerySelectField(u
'分类'
, query_factory
=
get_category_factory([
'id'
,
'name'
]), get_label
=
'name'
)
tags
=
TagListField(u
'标签'
, validators
=
[Required()])
content
=
PageDownField(u
'正文'
, validators
=
[Required()])
submit
=
SubmitField(u
'发布'
)
...
在views.py中处理表单就很方便了:
def
edit_article():
"""编辑文章"""
form
=
ArticleForm()
if
form.validate_on_submit():
article
=
Article(title
=
form.title.data, content
=
form.content.data)
article.tags
=
form.tags.data
article.category
=
form.category.data
try
:
db.session.add(article)
db.session.commit()
except
:
db.session.rollback()
return
render_template(
'dashboard/edit.html'
, form
=
form)
def
edit_article():
"""编辑文章"""
form
=
ArticleForm()
if
form.validate_on_submit():
article
=
Article(title
=
form.title.data, content
=
form.content.data)
article.tags
=
form.tags.data
article.category
=
form.category.data
try
:
db.session.add(article)
db.session.commit()
except
:
db.session.rollback()
return
render_template(
'dashboard/edit.html'
, form
=
form)
|
代码是不是很简洁了?^_^。。.
当然了写一个完整的WTForms扩展还是很麻烦的。这里只是刚刚入门。可以看官方扩展QuerySelectField的源码。。。 效果:
最后此篇关于在Python的Flask中使用WTForms表单框架的基础教程的文章就讲到这里了,如果你想了解更多关于在Python的Flask中使用WTForms表单框架的基础教程的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在遵循Flask-potion教程并尝试保护我的api。我一直试图找出如何在User端点上设置权限,以使一个User无法查看另一个User的记录。这是我的代码: class UserResourc
项目设置 Python 3.5.3 flask 0.12.2 目录 . ├── Core │ ├── BackgroundProcessManager.py │ ├── FirebaseDat
我正在构建 flask 应用程序并决定这次尝试应用程序工厂方法,但是遇到了 flask 迁移的麻烦并且无法找出简单的解决方案。 请注意,我想将配置位置作为选项传递给脚本 管理.py: manager
我尝试通过以下示例代码来熟悉Flask-APScheduler插件:https://github.com/viniciuschiele/flask-apscheduler/blob/master/ex
我一周前刚刚了解了 Flask 和 JWT,所以我真的需要一些帮助。有人可以解释一下flask-jwt和flask-jwt-extended之间的区别吗? 最佳答案 Flask-JWT 没有那么多功能
我是 Flask 的新手,我只是想用它创建一个简单的市场。我的网站上有三种类型的用户 [卖家、买家、管理员]。我认为每种类型的用户都应该有自己的注册和登录,因为他们的角色应该提供不同类型的信息。另一方
基本上,我想做一些非常简单的事情:我想创建一个用于删除数据库中条目的表单。 模板正在创建一个包含所有条目的html表,没有任何麻烦。我现在的问题是:如何将其转换为每行都有链接的表单。 当然,我可以通过
我对Flask来说非常陌生,其中一个基本要求是我需要SEO友好的URL。 我说一条路线 @app.route('/sales/') @app.route(/sales/) def get_sales(
一直在为用户管理系统开发Flask-user,但是我看不到自定义登录页面和注册页面的方法。我使用pip安装了flask-user pip install flask-user 任何帮助,将不胜感激 最
我有一个奇怪的情况,不知道如何找到问题。 我已经创建了一个这样的蓝图 reportjobsmod = Blueprint('jobreports', __name__, url_prefix='/jo
我认为在 Flask 中拥有实例变量的正确方法是添加用户和 session ,但我正在尝试测试一个概念,我还不想经历所有这些。我试图让一个网络应用程序将图像加载到一个变量中,然后可以对其执行不同的图像
select = SelectField("City") form.select.choices = [(places['name'], places['name']) for places in p
这个问题在这里已经有了答案: Provide extra information to Flask's app.logger (2 个回答) 3年前关闭。 我正在运行一个 flask 应用程序。我想写
我当时正在编程一个非常不错的api,使用json从游戏服务器到我的网站空间获取一些json数据, 但是每次我使用angular发送请求时,我都会得到以下信息:127.0.0.1--[20 / Mar
我已经开发了一个上传表单,以将特定的.xlsx文件作为上传。要求是要处理非xlsx上载的任何异常(例如zip,exe文件)。我正在使用pyexcel库读取上传内容。我尝试创建以下代码来处理此异常: e
我使用此功能在网站上捕获404错误: @app.errorhandler(404) def page_not_found(e): logger.warning('User raised an
我正在尝试同时使用 Flask Restful 和 Flask SocketIO。我已经制作了一个 Flask Restful 应用程序,但现在我想使用 Flask SocketIO 在客户端和我的服
我有一些 Flask 应用程序,我通过设置 FLASK_APP 来运行它们。环境变量和调用 flask run .自 FLASK_DEBUG也设置了,每当我更改一些代码时,应用程序都可以方便地重新加载
我目前正在使用 Flask 构建一个应用程序。我正在努力访问 Flask 实例“app”以及 Flask-mail 实例“mail”。 下面是我的项目的样子: └── my-project ├
Remember-me是 parameter flask_login.login_user(user, remember=False, duration=None, force=False, fres
我是一名优秀的程序员,十分优秀!