Как использовать поле FieldList WFForms для FormFields?

Я создаю веб-сайт, используя Flask, в котором я использую WTForms. В форме я теперь хочу использовать FieldList из FormFields следующим образом:

class LocationForm(Form):
    location_id = StringField('location_id')
    city = StringField('city')

class CompanyForm(Form):
    company_name = StringField('company_name')
    locations = FieldList(FormField(LocationForm))

чтобы дать людям возможность войти в компанию с двумя местоположениями (динамическое добавление местоположений происходит позже). Я делаю это на передней стороне:

<form action="" method="post" role="form">
    {{ companyForm.hidden_tag() }}
    {{ companyForm.company_name() }}
    {{ locationForm.location_id() }}
    {{ locationForm.city() }}
    {{ locationForm.location_id() }}
    {{ locationForm.city() }}
    <input type="submit" value="Submit!" />
</form>

Итак, отправьте, я распечатаю адреса:

print companyForm.locations.data

но я получаю

[{'location_id': u'', 'city': u''}]

Я могу распечатать значения первого местоположения с помощью locationForm (см. ниже), но я до сих пор не знаю, как получить данные второго местоположения.

print locationForm.location_id.data
print locationForm.city.data

Таким образом, список местоположений имеет один dict с пустыми значениями, но:

  • Почему в списке местоположений есть только один, а не два dicts?
  • И почему значения в местоположении dict пусты?

Кто-нибудь знает, что я здесь делаю неправильно? Все советы приветствуются!

Ответ 1

Для начала есть аргумент FieldList под названием min_entries, который сделает пространство для ваших данных:

class CompanyForm(Form):
    company_name = StringField('company_name')
    locations = FieldList(FormField(LocationForm), min_entries=2)

Это позволит настроить список так, как вам нужно. Затем вы должны визуализировать поля непосредственно из свойства locations, поэтому имена генерируются правильно:

<form action="" method="post" role="form">
    {{ companyForm.hidden_tag() }}
    {{ companyForm.company_name() }}
    {{ companyForm.locations() }}
    <input type="submit" value="Submit!" />
</form>

Посмотрите на визуализированный html, входы должны иметь имена типа locations-0-city, таким образом WTForms узнает, что именно.

В качестве альтернативы для пользовательской рендеринга элементов do

{% for l in companyForms.locations %}
{{ l.form.city }}
{% endfor %}

(только в wtforms l.city является сокращением для l.form.city. Однако этот синтаксис, похоже, сталкивается с Jinja, и там необходимо использовать явный l.form.city в шаблоне.)

Теперь, чтобы подготовить предоставленные данные, просто создайте CompanyForm и итерации по местоположениям:

for entry in form.locations.entries:
    print entry.data['location_id']
    print entry.data['city']