Динамически добавлять поля ввода с помощью wtforms

Я не совсем уверен, как подходит этот вопрос. Надеюсь, я доберусь туда.

Например, у меня есть таблица, полная адресов на странице. Количество их динамическое (может быть 5 или 10 или любое другое количество). И я хочу возможность редактировать их на одной странице.

Мой подход заключался в создании формы с wtforms для редактирования одного адреса и умножения это в jinja2 for loop и добавить к свойствам html name и id loop.index0 из itereation, поэтому я могу извлечь каждую строку данных вручную и верните его в мою форму, когда я хочу его оценить.

Таким образом, форма для этого примера будет выглядеть следующим образом:

class AdressForm(Form):
    name = TextField()

Итак, теперь мой шаблон aproach выглядит следующим образом (разбивайте на одно поле ввода):

{% for address in addresses %}
    {{ forms.render_field(addressform.name, id = "name_" ~ loop.index0, 
                          name = "name_" ~ loop.index0, value = address.name) }}
{% endfor %}

(forms.render_field - это просто макрос, чтобы указать правильные классы для функции поля wtforms, как они используются во многих учебниках)

Так что это не работает, так как вы не можете передать параметр name вручную для функции поля, так как wtforms создают name html-параметр из variblameame из встроенной формы.

Итак, есть способ добавить префикс или постфикс к имени формы, которую я хочу отобразить. Или это XY-проблема, и мой подход не соответствует действительности.

или я делаю все это самостоятельно (я действительно стараюсь избегать этого)

Ответ 1

WTForms имеет мета-поле FormField и другое мета-поле FieldList. Эти два вместе взятых получат то, что вы хотите:

class AddressEntryForm(FlaskForm):
    name = StringField()

class AddressesForm(FlaskForm):
    """A form for one or more addresses"""
    addresses = FieldList(FormField(AddressEntryForm), min_entries=1)

Чтобы создать записи в AddressesForm, просто используйте список словарей:

user_addresses = [{"name": "First Address"},
                  {"name": "Second Address"}]
form = AddressesForm(addresses=user_addresses)
return render_template("edit.html", form=form)

Затем в своем шаблоне просто переберите формы:

{% from 'your_form_template.jinja' import forms %}
{% for address_entry_form in form.addresses %}
    {{ address_entry_form.hidden_tag() }}
    {# Flask-WTF needs 'hidden_tag()' so CSRF works for each form #}
    {{ forms.render_field(address_entry_form.name) }}
{% endfor %}

WTForms автоматически будет правильно добавлять префиксы к именам и идентификаторам, поэтому, когда вы отправите данные обратно, вы сможете просто получить form.addresses.data и получить список словарей с обновленными данными.

Ответ 2

Ответ шона Виейры отлично работает для StringFields (ранее TextField), но с динамикой все становится немного сложнее SelectFields. Для тех, кто интересуется тем, как реализовать динамический SelectFields с wtforms, см. fooobar.com/info/8646066/...