我想制作一个字段数量不稳定的表单,以便用户可以根据需要添加尽可能多的新字段。 在不提前知道字段数量的情况下,如何获取 Python 端的所有表单数据(通过 WTForms)?
forms.py
class Form(FlaskForm):
field = StringField('field')
submit = SubmitField('submit')
HTML
<!-- I want my form to be viewed in Bootstrap Modal. -->
<div class="modal" tabindex="-1">
<div class="modal-body">
<form name="create-form" method="POST">
<div class="input-group">
{{ form.hidden_tag() }}
{{ form.field(class="form-control") }}
<!-- The place to insert additional fields -->
{{ form.submit(class="btn btn-outline-secondary) }}
</div>
</form>
<button id="add" type="button" class="btn btn-outline-secondary">Add</button>
</div>
</div>
<template id="new-field">
{{ form.field(class="form-control") }}
</template>
JS
modal.querySelector('#add').addEventListener('click', (ev) => {
modal.querySelector(/*Place to insett*/).before(/*new field from <template>*/);
});
modal.querySelector('form').addEventListener('submit', async (ev) => {
ev.preventDefault();
let form = modal.querySelector('form');
let resp = await fetch('/ajax', {method: 'POST', body: new FormData(form)});
});
routes.py
@bp.route('/ajax', methods=['GET', 'POST'])
def ajax():
# request.form contains all values
form = Form()
if form.validate():
# form.data has the only one value (from first field)
return {}
return {}
是的,似乎我需要为每个输入提供唯一的 wtf 字段。好吧,回到绘图板。
forms.py
class Form(FlaskForm):
field = StringField('field')
submit = SubmitField('submit')
def add_filed(self, i):
field = StringField(f'field{i}')
setattr(self.__class__, f'field{i}', field)
return self.__class__()
HTML
<template id="new-field">
{{ form.add_field(7)|attr("field7")(class="form-control") }}
</template>
什么也没有。
TypeError: 'UnboundField' object is not callable
再一次尝试:
modal.querySelector('#add').addEventListener('click', async (ev) => {
// At this point I'm sending ajax-request to call Form.add_field(7)
// on the Python side, bu as result I got {'field': 'value', 'field7': None}.
modal.querySelector(/*Place to insett*/).before(/*new field from <template>*/);
});
我错过了什么? 我读过很多有关此的主题,但没有明白。
谢谢。
遇到的问题源于 Flask-WTF 表单在服务器端生成,而尝试在客户端动态添加字段。尽管尝试动态添加字段,但服务器并不知道这些更改,因此它只处理最初在表单定义中指定的字段。
为了解决这个问题,需要采取不同的方法:
1. 使用 JavaScript 处理动态字段:
- 不要试图动态添加 WTF 字段。 让的 JavaScript 代码将所有动态添加的字段的名称和值存储在一个数组或对象中。
- 在表单中添加一个隐藏字段, 用于存储 JavaScript 生成的动态字段数据(例如,作为一个 JSON 字符串)。
- 在服务器端, 从隐藏字段中检索动态字段数据,并将其解析为 Python 数据结构(例如,列表或字典)。
示例代码:
HTML (
templates/index.html
):
<div class="modal" tabindex="-1">
<div class="modal-body">
<form name="create-form" method="POST">
<div class="input-group">
{{ form.hidden_tag() }}
{{ form.csrf_token }}
{{ form.field(class="form-control") }}
<div id="dynamic-fields"></div>
<button type="button" id="add" class="btn btn-outline-secondary">Add</button>
{{ form.submit(class="btn btn-outline-secondary") }}
</div>
</form>
</div>
</div>
<template id="new-field-template">
<div class="input-group">
<input type="text" name="dynamic_fields[]" class="form-control">
</div>
</template>
<script>
const addButton = document.getElementById('add');
const dynamicFieldsContainer = document.getElementById('dynamic-fields');
const newFieldTemplate = document.getElementById('new-field-template');
addButton.addEventListener('click', () => {
const newField = newFieldTemplate.content.cloneNode(true);
dynamicFieldsContainer.appendChild(newField);
});
</script>
Python (
forms.py
):
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
class MyForm(FlaskForm):
field = StringField('Field')
submit = SubmitField('Submit')
Python (
routes.py
):
from flask import render_template, request, jsonify
from .forms import MyForm
@app.route('/', methods=['GET', 'POST'])
def index():
form = MyForm()
if form.validate_on_submit():
static_field = form.field.data
dynamic_fields = request.form.getlist('dynamic_fields[]')
# 处理表单数据...
print("Static Field:", static_field)
print("Dynamic Fields:", dynamic_fields)
return jsonify({'message': 'Form submitted successfully!'})
return render_template('index.html', form=form)
解释:
-
JavaScript 动态添加字段:
当用户点击 "Add" 按钮时,JavaScript 会克隆一个新的输入字段并将它添加到
dynamic-fields
容器中。所有动态添加的字段都使用相同的名称dynamic_fields[]
,以便在服务器端方便地检索。 -
服务器端处理动态数据:
在 Flask 路由中,
request.form.getlist('dynamic_fields[]')
用于获取所有名为dynamic_fields[]
的字段的值,并将它们存储在一个列表中。
通过这种方法,可以有效地处理动态添加的表单字段,并将其数据发送到 Flask 服务器进行处理。
标签:python,flask,wtforms From: 78849996