嵌套的 WTForms FieldList 在字段中产生 HTML

Nested WTForms FieldList results in HTML in fields

我在 上看到了相同的奇怪行为,其中我的原始字段使用 HTML 而不是默认值进行渲染。在另一个示例中,基本上在单个 FormField 上有一个 FieldList 的一层深层堆叠。在我的例子中,我在 FormField 上的 FieldList 上创建 FieldList 的二维结构。我不知道我在哪里。

app.py

import os
from flask import Flask, redirect, render_template, request, send_file, url_for
from flask_wtf import FlaskForm
from flask_wtf.csrf import CSRFProtect
from wtforms import FieldList, FormField, RadioField,  TextAreaField, validators

app = Flask(__name__)
csrf = CSRFProtect(app)
SECRET_KEY = os.urandom(32)
app.config['SECRET_KEY'] = SECRET_KEY

#region FORMS
class TestCaseItem(FlaskForm) :
    pass_fail_radio = RadioField( '' , choices=[('Pass','Pass'), ('Fail','Fail')] ,  default='Pass' , validators=[validators.DataRequired()] )
    failure_message = TextAreaField(default='')

class TestCaseForm(FlaskForm) :
    test_items = FieldList( FormField( TestCaseItem ))

class ManualTestForm(FlaskForm):
    test_cases = FieldList( FormField(TestCaseForm))
#endregion

@app.route("/" , methods = ['POST', 'GET'])
def index():
    form = ManualTestForm()

    test_cases = ["test case {}".format(i) for i in range(5)]
    devices    = ["device {}".format(i) for i in range(3)]

    # Expand the field list for each test case
    for tc in test_cases :
        tcf = TestCaseForm()
        # expand its field list for each test device
        for device in devices :
            tci = TestCaseItem()
            tci.failure_message = 'abc'
            tcf.test_items.append_entry( tci )
        form.test_cases.append_entry( tcf )

    return render_template('test_template.html', form=form, test_cases=test_cases, devices=devices )

if __name__ == "__main__" :
    app.run(debug=True, port=5001) # http://127.0.0.1:5001

templates/test_template.html

<html>
<head>
</head>
<body>
  <h1>Manual Test Submission</h1>
  <h2>Test Suite</h2>
  <form  method="post">
    {{ form.csrf_token }}
    <!--TEST CASES-->
    <table>
      <tr>
        <th>Test Case ID</th>
        {% for test_item in form.test_cases[0].test_items %}
        {% set device = devices[loop.index0] %}
        <th>TC Status: {{device}}</th>
        <th>TC Input: {{device}}</th>{% endfor %}
      </tr>
      {% for test_case in form.test_cases %}
      {{test_case.hidden_tag()}}
      <tr>
        <td>{{ test_cases[ loop.index0 ]}}</td>
        {% for test_item in test_case.test_items %}
        <td>{{ test_item.pass_fail_radio }}</td>
        <td>{{ test_item.failure_message }}</td>{% endfor %}
      </tr>{% endfor %}
    </table>
  </form>
</body>
</html>

在您的视图中以通常的方式设置所有字段值,但在您的模板中对属于嵌套表单的字段使用字段 .data 属性:

{% for test_case in form.test_cases %}
  {{ test_case.hidden_tag() }}
  {{ test_cases[loop.index0] }}

  {% for test_item in test_case.test_items %}
    {{ test_item.pass_fail_radio.data }}
    {{ test_item.failure_message.data }}
  {% endfor %}

{% endfor %}

就其价值而言,在处理嵌套的 FieldList 时还有另一个陷阱:如果您以逻辑方式构建表单,字段 idname 属性将不会完全命名空间,因为.append_entry() 的工作方式。因此,预期值不会被发布,验证也会中断。

破损:

form = RecipientsForm()

for proprietor in proprietors:
    proprietor_form = ProprietorForm()
    # Set proprietor name in hidden input field.
    proprietor_form.prop_name = proprietor['name']
    # populate and append addresses to proprietor form.
    for address in proprietor['addresses']:
        address_form = AddressForm()
        address_form.address = address['address']
        address_form.address_type = address['type']
        proprietor_form.addresses.append_entry(address_form)
    form.proprietors.append_entry(proprietor_form)

作品:

form = RecipientsForm()

proprietors = proprietor_api_call()
# Populate and append proprietors to Recipients form.
for idx, proprietor in enumerate(proprietors):
    proprietor_form = ProprietorForm()
    proprietor_form.prop_name = proprietor['name']
    form.proprietors.append_entry(proprietor_form)
    # Populate and append addresses to Proprietor form.
    for address in proprietor['addresses']:
        address_form = AddressForm()
        address_form.address = address['address']
        address_form.address_type = address['type']
        form.proprietors[idx].addresses.append_entry(address_form)