表单是和用户交互最常见的方式之一,本章涉及的Python包由WTForms、Flask-WTF、Flask-CKEditor。(p104)
通过标签创建表单,
标签创建字段。
<form method="post">
<input type="text" name="username" placeholder="用户名">
form>
WTForms:支持在Python中使用类定义表单,然后通过类定义生成对应的HTML代码。
Flask-WTF在Flask中集成了表单数据解析、CSRF保护、文件上传等功能。
# 设置密钥,flask-wtf使用程序密钥来对csrf令牌进行签名(?)
app.secret_key = 'secret string'
定义表单类:
from wtforms import From
class LoginForm(Form):
...
输出HTML代码:
>>> form = LoginForm()
>>> form.username() # 假设在类中定义了username字段
>>> form.username.label()
id
和name
属性,其他属性可以:
在模板中渲染表单:我们需要把表单类实例传入模板,然后再模板中调用表单类的属性即可获取字段对应的HTML代码。
return render_template('basic.html', form=form)
<form method="post">
{{ form.csrf_token }}
{{ form.username.label }}
{{ form.username(class='form-contorl') }}
form>
CSRF字段:在提交表单后会自动验证该字段,为使验证通过,需渲染。
可以手动编写HTML表单的代码,name属性与表单类保持一致。
1 过程:解析请求 --> 转换为Python数据类型 --> 验证 --> 处理。
2 提交表单:在HTML中,当标签声明的表单中类型为submit的提交字段被点击时,就会创建一个提交表单的HTTP请求。
HTML表单中控制提交行为的属性:action(目标URL),method(HTTP请求方法),enctype(表单数据编码类型)。(p112)
3 验证表单数据:
validate()
方法,错误消息会存储到实例的errors
属性对应的字典中。>>> form.errors # 错误消息字典
>>> form.username.data
4 渲染错误消息:WTForms会把错误消息添加到表单类的errors
属性中,这是一个匹配作为表单字段的类属性到对应的错误消息列表的字典。
>>> form.username.errors
简化表单处理过程的技巧,以及表单的一些非常规应用。
1 设置错误消息语言:如下,所有继承MyBaseForm
的表单类,将使用新设置的错误消息默认语言。
from flask_wtf import FlaskForm
app = Flask(__name__)
app.config['WTF_I18N_ENABLED'] = False
class MyBaseForm(FlaskForm):
class Meta:
locals = ['zh']
class HelloFrom(MyBaseForm):
...
疑惑:类内部再定义一个Meta类是什么操作?
2 使用宏渲染表单:在模板中渲染表单时,存在大量的重复工作:获取定义、获取
定义、渲染错误消息。为了避免每一个字段重复这些代码,可以创建一个宏。(p120)
{% macro form_field(field) %}
{{ field.label}}
{{ field(**kwargs) }}
{% if field.errors %}
{% for error in field.errors %}
{{ error }}
{% endfor %}
{% endif %}
{% end macro %}
3 自定义验证器:验证器是指在定义字段时传入validators参数列表的可调用对象,接受form
和field
(字段)两个位置参数。(p121)
ValidateionError
异常。若需支持参数,可用工厂函数形式。工厂函数:返回一个可调用对象的函数。
4 文件上传:
字段的type
属性值设置为file。
<input type="file">
可以使用Flask-WTF提供的FileField
类创建文件上传字段,验证器包括FileRequired
(是否包含文件对象)和FileAllowed
(验证文件类型)。此外,可以通过限制请求报文的最大长度来限制文件大小:
app.config['MAX_CONTENT_LENGTH'] = 3 * 1024 * 1024
request.files.get('photo')
# 在Flask-WTF中
f = form.photo.data
疑惑:使用uuid重命名了文件,后续如何找到这个文件呢,将文件名保存到数据库?(毕竟文件名是随机生成的)
多文件:单击一次按钮,可以一次性选择多个文件并上传。
心得笔记:感觉文件上传这一块弯弯绕绕挺多的,一时间看得有点懵。
5 使用Flask-CKEditor集成富文本编辑器:对我也是一个黑盒子 的感觉(p129)
疑惑:文本应该以什么形式保存?
6 单个表单多个提交按钮:
如“发布文章”和“保存草稿”,需根据按钮做出不同的处理。可在表单类创建多个SubmitField
类型的字段,只有被点击的字段才会出现在reqeust.form
字典中,而调用data
属性时则会被处理为True
或False
。
if form.validata_on_submit():
if form.save.data:
...
if form.publish.data:
...
7 单个页面多个表单:
问题是判断当前被提交的是哪个表单。
注:表单提交请求的目标URL通过
action
属性设置。
表单这一节的内容比较丰富、繁杂,涉及的调包操作也较多,看完后仍有不少细节之处理解模糊。偶尔会体会到,之前看过的《Python工匠》对于我理解本书内容的帮助。
学这节的时候,我看得多,动手少,难免看了后面忘前面。一节书看完,再去看相关的源代码时却仍有些看不懂。