如何使用 FormFields 的 WTForms FieldList?
How to use a WTForms FieldList of FormFields?
我正在使用 Flask in which I use WTForms 构建网站。在一个表单中,我现在想使用一个 FormFields 的 FieldList,如下所示:
class LocationForm(Form):
location_id = StringField('location_id')
city = StringField('city')
class CompanyForm(Form):
company_name = StringField('company_name')
locations = FieldList(FormField(LocationForm))
所以为了让人们能够进入一家有两个地点的公司(地点的动态添加稍后出现)我在正面这样做:
<form action="" method="post" role="form">
{{ companyForm.hidden_tag() }}
{{ companyForm.company_name() }}
{{ locationForm.location_id() }}
{{ locationForm.city() }}
{{ locationForm.location_id() }}
{{ locationForm.city() }}
<input type="submit" value="Submit!" />
</form>
所以在提交时我打印了位置:
print companyForm.locations.data
但我明白了
[{'location_id': u'', 'city': u''}]
我可以使用 locationForm(见下文)打印第一个位置的值,但我仍然不知道如何获取第二个位置的数据。
print locationForm.location_id.data
print locationForm.city.data
所以位置列表确实有一个空值字典,但是:
- 为什么位置列表只有一个而不是两个字典?
- 为什么位置字典中的值是空的?
有人知道我做错了什么吗?欢迎所有提示!
对于初学者来说,FieldList 有一个名为 min_entries
的参数,它将为您的数据生成 space:
class CompanyForm(Form):
company_name = StringField('company_name')
locations = FieldList(FormField(LocationForm), min_entries=2)
这将按照您需要的方式设置列表。接下来,您应该直接从 locations
属性 呈现字段,以便正确生成名称:
<form action="" method="post" role="form">
{{ companyForm.hidden_tag() }}
{{ companyForm.company_name() }}
{{ companyForm.locations() }}
<input type="submit" value="Submit!" />
</form>
查看呈现的 html,输入的名称应该类似于 locations-0-city
,这样 WTForms 就会知道哪个是哪个。
或者,对于元素的自定义呈现
{% for l in companyForms.locations %}
{{ l.form.city }}
{% endfor %}
(仅在 wtforms 中 l.city
是 shorthand for l.form.city
。但是,该语法似乎与 Jinja 冲突,因此有必要使用显式 l.form.city
在模板中。)
现在准备好提交的数据,只需创建 CompanyForm
并迭代位置:
for entry in form.locations.entries:
print entry.data['location_id']
print entry.data['city']
这是一个老问题,但仍然是一个好问题。
我想添加一个基于 Flask 的玩具数据库的工作示例(只是一个字符串列表),重点放在 Python 部分 - 如何使用可变数量的子表单初始化表单以及如何处理发布的数据。
这是 example.py
文件:
import flask
import wtforms
import flask_wtf
app = flask.Flask(__name__)
app.secret_key = 'fixme!'
# not subclassing from flask_wtf.FlaskForm
# in order to avoid CSRF on subforms
class EntryForm(wtforms.Form):
city = wtforms.fields.StringField('city name:')
delete = wtforms.fields.BooleanField('delete?')
class MainForm(flask_wtf.FlaskForm):
entries = wtforms.fields.FieldList(wtforms.fields.FormField(EntryForm))
submit = wtforms.fields.SubmitField('SUBMIT')
city_db = "Graz Poprad Brno Basel Rosenheim Torino".split() # initial value
@app.route("/", methods=['POST'])
def demo_view_function_post():
global city_db
form = MainForm()
if form.validate_on_submit():
city_db = [
entry['city'] for entry in form.entries.data
if entry['city'] and not entry['delete']]
return flask.redirect(flask.url_for('demo_view_function_get'))
# handle the validation error, i.e. flash a warning
return flask.render_template('demo.html', form=form)
@app.route("/")
def demo_view_function_get():
form = MainForm()
entries_data = [{'city': city, 'delete': False} for city in city_db]
entries_data.append({'city': '', 'delete': False}) # "add new" placeholder
form.process(data={'entries': entries_data})
return flask.render_template('demo.html', form=form)
这是 demo.html
文件:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Demo</title>
</head>
<body>
<h1>Subform demo</h1>
<p>Edit names / mark for deletion / add new</p>
<form method="post">
{{ form.csrf_token() }}
{% for entry in form.entries %}
{% if loop.last %}
<div>Add new:</div>
{% endif %}
<div>
{{ entry.city.label }} {{ entry.city() }}
{{ entry.delete() }} {{ entry.delete.label }}
</div>
{% endfor %}
{{ form.submit() }}
</form>
</body>
运行 与:FLASK_APP=example flask run
我正在使用 Flask in which I use WTForms 构建网站。在一个表单中,我现在想使用一个 FormFields 的 FieldList,如下所示:
class LocationForm(Form):
location_id = StringField('location_id')
city = StringField('city')
class CompanyForm(Form):
company_name = StringField('company_name')
locations = FieldList(FormField(LocationForm))
所以为了让人们能够进入一家有两个地点的公司(地点的动态添加稍后出现)我在正面这样做:
<form action="" method="post" role="form">
{{ companyForm.hidden_tag() }}
{{ companyForm.company_name() }}
{{ locationForm.location_id() }}
{{ locationForm.city() }}
{{ locationForm.location_id() }}
{{ locationForm.city() }}
<input type="submit" value="Submit!" />
</form>
所以在提交时我打印了位置:
print companyForm.locations.data
但我明白了
[{'location_id': u'', 'city': u''}]
我可以使用 locationForm(见下文)打印第一个位置的值,但我仍然不知道如何获取第二个位置的数据。
print locationForm.location_id.data
print locationForm.city.data
所以位置列表确实有一个空值字典,但是:
- 为什么位置列表只有一个而不是两个字典?
- 为什么位置字典中的值是空的?
有人知道我做错了什么吗?欢迎所有提示!
对于初学者来说,FieldList 有一个名为 min_entries
的参数,它将为您的数据生成 space:
class CompanyForm(Form):
company_name = StringField('company_name')
locations = FieldList(FormField(LocationForm), min_entries=2)
这将按照您需要的方式设置列表。接下来,您应该直接从 locations
属性 呈现字段,以便正确生成名称:
<form action="" method="post" role="form">
{{ companyForm.hidden_tag() }}
{{ companyForm.company_name() }}
{{ companyForm.locations() }}
<input type="submit" value="Submit!" />
</form>
查看呈现的 html,输入的名称应该类似于 locations-0-city
,这样 WTForms 就会知道哪个是哪个。
或者,对于元素的自定义呈现
{% for l in companyForms.locations %}
{{ l.form.city }}
{% endfor %}
(仅在 wtforms 中 l.city
是 shorthand for l.form.city
。但是,该语法似乎与 Jinja 冲突,因此有必要使用显式 l.form.city
在模板中。)
现在准备好提交的数据,只需创建 CompanyForm
并迭代位置:
for entry in form.locations.entries:
print entry.data['location_id']
print entry.data['city']
这是一个老问题,但仍然是一个好问题。
我想添加一个基于 Flask 的玩具数据库的工作示例(只是一个字符串列表),重点放在 Python 部分 - 如何使用可变数量的子表单初始化表单以及如何处理发布的数据。
这是 example.py
文件:
import flask
import wtforms
import flask_wtf
app = flask.Flask(__name__)
app.secret_key = 'fixme!'
# not subclassing from flask_wtf.FlaskForm
# in order to avoid CSRF on subforms
class EntryForm(wtforms.Form):
city = wtforms.fields.StringField('city name:')
delete = wtforms.fields.BooleanField('delete?')
class MainForm(flask_wtf.FlaskForm):
entries = wtforms.fields.FieldList(wtforms.fields.FormField(EntryForm))
submit = wtforms.fields.SubmitField('SUBMIT')
city_db = "Graz Poprad Brno Basel Rosenheim Torino".split() # initial value
@app.route("/", methods=['POST'])
def demo_view_function_post():
global city_db
form = MainForm()
if form.validate_on_submit():
city_db = [
entry['city'] for entry in form.entries.data
if entry['city'] and not entry['delete']]
return flask.redirect(flask.url_for('demo_view_function_get'))
# handle the validation error, i.e. flash a warning
return flask.render_template('demo.html', form=form)
@app.route("/")
def demo_view_function_get():
form = MainForm()
entries_data = [{'city': city, 'delete': False} for city in city_db]
entries_data.append({'city': '', 'delete': False}) # "add new" placeholder
form.process(data={'entries': entries_data})
return flask.render_template('demo.html', form=form)
这是 demo.html
文件:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Demo</title>
</head>
<body>
<h1>Subform demo</h1>
<p>Edit names / mark for deletion / add new</p>
<form method="post">
{{ form.csrf_token() }}
{% for entry in form.entries %}
{% if loop.last %}
<div>Add new:</div>
{% endif %}
<div>
{{ entry.city.label }} {{ entry.city() }}
{{ entry.delete() }} {{ entry.delete.label }}
</div>
{% endfor %}
{{ form.submit() }}
</form>
</body>
运行 与:FLASK_APP=example flask run