У меня есть приложение flask + wtforms, в котором я хочу, чтобы пользователи могли вводить как родительский объект, так и произвольное количество дочерних объектов. Я не уверен, как лучше всего динамически создавать новые поля ввода дочерней формы из пользовательского интерфейса.
Что у меня есть до сих пор
Ниже приведен полный рабочий пример. (Примечание: это искусственный пример выделения всех рабочих частей в одном файле .py, что делает код довольно беспорядочным. Извините.)
from flask import Flask, render_template_string
from flask_wtf import FlaskForm
from wtforms import FieldList, FormField, StringField, SubmitField
from wtforms.validators import InputRequired
# Here I'm defining a parent form, AuthorForm, and a child form, BookForm.
# I'm using the FieldList and FormField features of WTForms to allow for multiple
# nested child forms (BookForms) to be attached to the parent (AuthorForm).
class BookForm(FlaskForm):
title = StringField('title', validators=[InputRequired()])
genre = StringField('genre', validators=[InputRequired()])
# I'm defining a min_entry of 1 so that new forms contain a blank BookForm entry
class AuthorForm(FlaskForm):
name = StringField('name', validators=[InputRequired()])
books = FieldList(FormField(BookForm), min_entries=1)
submit = SubmitField('Save')
# Here's my Jinja template
html_template_string = """
<html>
<head><title>stackoverflow example</title></head>
<body>
<form action="" method="post" role="form">
{{ form.hidden_tag() }}
{{ form.name.label }} {{ form.name() }}
{% for book in form.books %}
<p>
{{ book.title.label }} {{ book.title() }}
{{ book.genre.label }} {{ book.genre() }}
{{ book.hidden_tag() }}
</p>
{% endfor %}
{{ form.submit() }}
</form>
</body>
</html>
"""
# Alright, let's start the app and try out the forms
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
@app.route('/', methods=['GET', 'POST'])
def index():
form = AuthorForm()
if form.validate_on_submit():
for book in form.books.data:
print(book)
return render_template_string(html_template_string, form=form)
if __name__ == '__main__':
app.run()
Где я застрял
Я знаю, как создавать новые дочерние записи (записи BookForm) на стороне сервера. Я мог бы просто передать пустые словари в свою форму, и WTForms сгенерировал бы для меня входные данные:
...
form = AuthorForm()
form.books.append_child({})
form.books.append_child({})
form.books.append_child({})
...
Бам, теперь на моей странице есть поля ввода для трех книг, и я мог бы предварительно заполнить их данные. WTForms генерирует содержимое ввода формы перед отображением страницы. Он обрабатывает все идентификаторы, необходимые для каждого входа и т. д.
Если я хочу, чтобы пользователь мог щелкнуть кнопку и добавить новые экземпляры ввода BookForm со стороны пользователя после того, как страница была отрисована… как мне это сделать? Должен ли я сам вручную создавать поля ввода в JavaScript, используя в качестве эталона то, что было сгенерировано WTForms? Это кажется грязным и склонным к поломке или, по крайней мере, к уродливому коду.
Есть ли способ для WTForms отображать HTML для новых входных данных по мере необходимости, управляя уникальностью идентификаторов входных тегов и т. Д.? Я мог бы отправить что-то обратно на сервер, чтобы добавить пустые записи в форму и повторно отобразить страницу, но это лишило бы меня всего моего существующего пользовательского ввода, поэтому на самом деле это не работает. Этот вопрос Stackoverflow предполагает то же самое в комментариях, и то же самое возражение поднятый.
Если это должно быть сделано уродливым ручным способом, то я могу это сделать. Я просто не хочу использовать плохой подход, когда есть лучшее (и, возможно, даже официальное) решение этой проблемы.
Это в основном то, для чего был создан jquery. — person daveruinseverything schedule 29.04.2019
Этот ответ делает что-то вроде того, что требуется. Клонирование соответствующих полей в js, увеличение идентификаторов и рендеринг «новой» разметки — единственный разумный способ сделать это, я думаю. — person daveruinseverything schedule 29.04.2019
