Вопросы

Динамически добавлять новые записи WTForms FieldList из пользовательского интерфейса

У меня есть приложение 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

Похожие записи

Автоматическое применение изменений при сохранении в vscode

admin

Препроцессор GCC не работает? Время компиляции больших файлов с комментариями или без них

admin

Почему при использовании массивов текстур не нужно привязывать семплер к шейдеру?

admin

Тайм-аут клона Gitlab runner после traefik (относительный путь)

admin

Как лучше всего защитить исходный код Python приложения Flask от копирования?

admin

Только GitLab + Composer + Private Repo + SSH

admin