英文:
WTForms Editable Table 'CSRFTokenField' is not iterable
问题
我遵循了这个示例来创建一个可编辑的表单,用于显示/编辑我的数据库中的数据。我不明白为什么提交按钮位于行表单类内部,所以我将它放在了表单类中。
我一直收到TypeError: argument of type 'CSRFTokenField' is not iterable
的错误,我怀疑这与使用FieldList有关,但我卡住了。我找到了一个类似的问题,但没有得到答案。
我正在使用Flask蓝图结构。
forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, FieldList, FormField, SelectField, BooleanField, FloatField
class RowForm(FlaskForm):
col1 = SelectField('col1', choices=[(0, 'YES'), (1, 'NO')])
col2 = FloatField('col2')
col3 = StringField('col3')
class TableForm(FlaskForm):
title = StringField('title')
rows = FieldList(FormField(RowForm))
submit = SubmitField('submit')
views.py
#...imports
@test.route('/table_test', methods=['GET', 'POST'])
def show_test_table():
table_form = TableForm()
row_static_list = RowTest.query.all()
# 循环遍历查询以预填充可编辑字段的值
for row in row_static_list:
row_form = RowForm()
# 将可编辑字段添加到行表单中
row_form.col1 = 1 if row.col1 else 0
row_form.col2 = row.col2
row_form.col3 = row.col3
table_form.rows.append_entry(row_form)
if request.method == 'POST':
print(table_form.csrf_token)
# 如果表单有效,更新SensorConfig
if table_form.validate_on_submit():
print('***************\nFORM IS VALID\n***************')
else:
print('***************\nFORM IS NOT VALID\n***************')
return render_template('test/table_form.html', table_form=table_form, rows_fixed=row_static_list)
table_form.html
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}TESTING TABLE{% endblock %}
{% block head %}
{{ super() }}
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css') }}">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='dropdown.css') }}">
{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Testing Table Form</h1>
</div>
<div>
<form action method="post" name="TableForm">
{{ table_form.csrf_token }}
{{ table_form.submit }}
<div>
<table class="content-table">
<thead>
<tr>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
</tr>
</thead>
<tbody>
{% for r, r_fixed in zip(table_form.rows, rows_fixed) %}
<tr>
<td>{{ r.col1 }}</td>
<td>{{ r.col2 }}</td>
<td>{{ r.col3 }}</td>
<td>{{ r_fixed.col4 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</form>
</div>
{% endblock %}
**注意:**上面的zip
是必需的,否则固定的值会加载为空。请参见这里。
英文:
I followed this example to create an editable table form to display data/edit from my database. I don't understand why the submit button is inside the row form class, so I put it in the table form class.
I keep getting TypeError: argument of type 'CSRFTokenField' is not iterable
, which I suspect has something to do with using a FieldList, but I'm stuck. I found a similar question, but it was never answered.
I am using the flask blueprint structure.
forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, FieldList, FormField, SelectField, BooleanField, FloatField
class RowForm(FlaskForm):
col1 = SelectField('col1',
choices=[(0, 'YES'), (1, 'NO')])
col2 = FloatField('col2')
col3 = StringField('col3')
class TableForm(FlaskForm):
title = StringField('title')
rows = FieldList(FormField(RowForm))
submit = SubmitField('submit')
views.py
#...imports
@test.route('/table_test', methods=['GET', 'POST'])
def show_test_table():
table_form = TableForm()
row_static_list = RowTest.query.all()
# looping through query to prepopulate values for editable fields
for row in row_static_list:
row_form = RowForm()
# adding editable fields to Row Form
row_form.col1 = 1 if row.col1 else 0
row_form.col2 = row.col2
row_form.col3 = row.col3
table_form.rows.append_entry(row_form)
if request.method == 'POST':
print(table_form.csrf_token)
# if form is valid, update SensorConfig with changes
if table_form.validate_on_submit():
print('***************\nFORM IS VALID\n***************')
else:
print('***************\nFORM IS NOT VALID\n***************')
return render_template('test/table_form.html', table_form=table_form, rows_fixed=row_static_list)
table_form.html
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}TESTING TABLE{% endblock %}
{% block head %}
{{ super() }}
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css') }}">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='dropdown.css') }}">
{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Testing Table Form</h1>
</div>
<div>
<form action method="post" name="TableForm">
{{ table_form.csrf_token }}
{{ table_form.submit }}
<div>
<table class="content-table">
<thead>
<tr>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
</tr>
</thead>
<tbody>
{% for r, r_fixed in zip(table_form.rows, rows_fixed) %}
<tr>
<td>{{ r.col1 }}</td>
<td>{{ r.col2 }}</td>
<td>{{ r.col3 }}</td>
<td>{{ r_fixed.col4 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</form>
</div>
{% endblock %}
NOTE: The zip
above is required else the fixed values load as blank. See here.
答案1
得分: 1
致敬 r/Flask Discord 上的 taylor_prime 和 dnswrsrx 提供的帮助。 解决方案是将Form用作`RowForm`的基类,并将FlaskForm用作`TableForm`的基类。 将FlaskForm用作`RowForm`的基类似乎为添加到`FlaskForm`的每个新实例添加了一个新的csrf_token。
将**forms.py**调整为以下内容可以解决问题。
```python
from flask_wtf import Form, FlaskForm
from wtforms import StringField, SubmitField, FieldList, FormField, SelectField, BooleanField, FloatField
class RowForm(Form):
col1 = SelectField('col1',
choices=[(0, 'YES'), (1, 'NO')])
col2 = FloatField('col2')
col3 = StringField('col3')
class TableForm(FlaskForm):
title = StringField('title')
rows = FieldList(FormField(RowForm))
submit = SubmitField('submit')
英文:
Shoutout to taylor_prime and dnswrsrx on the r/Flask Discord for the help. The solution is to use Form as the Base Class for RowForm
and FlaskForm as the Base Class for TableForm
. Using FlaskForm as the Base Class for RowForm
seemed to add a new csrf_token for each new instance of RowForm
added to FlaskForm
.
Adjusting forms.py to the below fixed the problem.
from flask_wtf import Form, FlaskForm
from wtforms import StringField, SubmitField, FieldList, FormField, SelectField, BooleanField, FloatField
class RowForm(Form):
col1 = SelectField('col1',
choices=[(0, 'YES'), (1, 'NO')])
col2 = FloatField('col2')
col3 = StringField('col3')
class TableForm(FlaskForm):
title = StringField('title')
rows = FieldList(FormField(RowForm))
submit = SubmitField('submit')
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论