‘CSRFTokenField’ 不可迭代

huangapple go评论61阅读模式
英文:

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是必需的,否则固定的值会加载为空。请参见这里

‘CSRFTokenField’ 不可迭代

英文:

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 &#39;CSRFTokenField&#39; 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(&#39;col1&#39;,
                       choices=[(0, &#39;YES&#39;), (1, &#39;NO&#39;)])
    col2 = FloatField(&#39;col2&#39;)
    col3 = StringField(&#39;col3&#39;)


class TableForm(FlaskForm):
    title = StringField(&#39;title&#39;)
    rows = FieldList(FormField(RowForm))

    submit = SubmitField(&#39;submit&#39;)

views.py

#...imports

@test.route(&#39;/table_test&#39;, methods=[&#39;GET&#39;, &#39;POST&#39;])
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 == &#39;POST&#39;:
        print(table_form.csrf_token)
        # if form is valid, update SensorConfig with changes
        if table_form.validate_on_submit():
            print(&#39;***************\nFORM IS VALID\n***************&#39;)
        else:
            print(&#39;***************\nFORM IS NOT VALID\n***************&#39;)

    return render_template(&#39;test/table_form.html&#39;, table_form=table_form, rows_fixed=row_static_list)

table_form.html

{% extends &quot;base.html&quot; %}
{% import &quot;bootstrap/wtf.html&quot; as wtf %}

{% block title %}TESTING TABLE{% endblock %}

{% block head %}
{{ super() }}
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;{{ url_for(&#39;static&#39;, filename=&#39;styles.css&#39;) }}&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;{{ url_for(&#39;static&#39;, filename=&#39;dropdown.css&#39;) }}&quot;&gt;
{% endblock %}

{% block page_content %}
&lt;div class=&quot;page-header&quot;&gt;
    &lt;h1&gt;Testing Table Form&lt;/h1&gt;
&lt;/div&gt;

&lt;div&gt;
    &lt;form action method=&quot;post&quot; name=&quot;TableForm&quot;&gt;
        {{ table_form.csrf_token }}
        {{ table_form.submit }}
        &lt;div&gt;
            &lt;table class=&quot;content-table&quot;&gt;
                &lt;thead&gt;
                    &lt;tr&gt;
                        &lt;th&gt;Col 1&lt;/th&gt;
                        &lt;th&gt;Col 2&lt;/th&gt;
                        &lt;th&gt;Col 3&lt;/th&gt;
                        &lt;th&gt;Col 4&lt;/th&gt;
                    &lt;/tr&gt;
                &lt;/thead&gt;
                &lt;tbody&gt;
                    {% for r, r_fixed in zip(table_form.rows, rows_fixed) %}
                    &lt;tr&gt;
                        &lt;td&gt;{{ r.col1 }}&lt;/td&gt;
                        &lt;td&gt;{{ r.col2 }}&lt;/td&gt;
                        &lt;td&gt;{{ r.col3 }}&lt;/td&gt;
                        &lt;td&gt;{{ r_fixed.col4 }}&lt;/td&gt;
                    &lt;/tr&gt;
                    {% endfor %}
                &lt;/tbody&gt;
            &lt;/table&gt;
        &lt;/div&gt;
    &lt;/form&gt;    
&lt;/div&gt;
{% endblock %}

NOTE: The zip above is required else the fixed values load as blank. See here.

‘CSRFTokenField’ 不可迭代

答案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(&#39;col1&#39;,
                       choices=[(0, &#39;YES&#39;), (1, &#39;NO&#39;)])
    col2 = FloatField(&#39;col2&#39;)
    col3 = StringField(&#39;col3&#39;)


class TableForm(FlaskForm):
    title = StringField(&#39;title&#39;)
    rows = FieldList(FormField(RowForm))

    submit = SubmitField(&#39;submit&#39;)

huangapple
  • 本文由 发表于 2023年7月6日 22:11:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76629733.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定