Creación de un formulario con un número variable de subformularios repetidos en Flask / WTForms

Mi modelo actualmente tiene tres objetos relacionados (hay más, pero solo tres son relevantes para este problema). Usuario, red y correo electrónico. Lo que quiero poder hacer es tener un conjunto definido de Redes y permitir que cada Usuario tenga una dirección de correo electrónico en cada Red (estas son un poco más complejas, pero las he reducido a lo que creo que es relevante) .

class User(UserMixin, db.Model): """ The User object. """ __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) # email = db.Column(db.String(64), unique=True, index=True) username = db.Column(db.String(64), unique=True, index=True) password_hash = db.Column(db.String(128)) firstname = db.Column(db.String(64)) lastname = db.Column(db.String(64), unique=False, index=True) email = db.relationship('Email', backref='user') class Network(db.Model): __tablename__ = 'networks' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), index=True) emails = db.relationship('Email', backref='network', lazy='dynamic') class Email(db.Model): __tablename__ = 'emails' id = db.Column(db.Integer, primary_key=True) network_id = db.Column(db.Integer, db.ForeignKey('networks.id')) user_id = db.Column(db.Integer, db.ForeignKey('users.id')) address = db.Column(db.String(64)) 

Mi vista:

 @main.route('/edit-profile', methods=['GET', 'POST']) @login_required def edit_profile(): form = EditProfileForm(obj=current_user) form.email.min_entries=Network.query.count() if form.validate_on_submit(): form.populate_obj(current_user) db.session.add(current_user) db.session.commit() flash("Your profile has been updated.") return redirect(url_for('.user', username=current_user.username)) return render_template('edit_profile.html', form=form) 

Y formas:

 class EmailForm(Form): id = HiddenField('Id') address = StringField('Address', validators=[DataRequired(), Email()]) network = QuerySelectField(query_factory=get_networks) class EditProfileForm(Form): username = StringField('Username', validators=[Length(0, 64), Regexp('[A-Za-z0-9_\.\-]'), DataRequired()]) firstname = StringField('First name', validators=[Length(0, 64), DataRequired()]) lastname = StringField('Last name', validators=[Length(0, 64), DataRequired()]) email = ModelFieldList(FormField(EmailForm), model=Email) submit = SubmitField('Submit') 

El HTML de la forma externa:

 {% extends "base.html" %} {% import "bootstrap/wtf.html" as wtf %} {% block title %}Edit Profile{% endblock %} {% block page_content %}  
{{ wtf.quick_form(form) }}
{% endblock %}

Esto es lo que parece tanto en Chrome como en Firefox:

    Captura de pantalla de la forma de aspecto horrible

    Así que obviamente estoy haciendo algo mal, ya que:

    1. Los widgets de la subforma no se parecen en nada a los de la forma externa, y
    2. La subforma sigue mostrándose sobre la parte superior de la forma externa.

    ¿Dónde me he equivocado con esto? Intenté no usar wtf.quick_form () pero tampoco pude hacer que se viera bien manualmente. Para hacer eso, reemplacé el {{wtf.quick_form ()}} con esto:

       {{ form.username }}  {{ form.firstname }}  {{ form.lastname }} 
    {{ form.email.label }} {% for e in form.email %} {% endfor %}
    Network Address {{ form_button(url_for('main.add_email'), icon ('plus')) }}
    {{ e.network }} {{ e.address }} {{ form_button(url_for('main.remove_email', id=loop.index), icon ('remove')) }}
    {{ form.submit }}

    Cuando renderizo esto, aparece como se muestra abajo en mi navegador:

    Captura de pantalla de forma incorrecta.

    Esto tiene la virtud de ser coherente, pero no es el aspecto que deseo obtener utilizando flask-bootstrap. Estoy luchando para averiguar qué enfoque me llevará a donde quiero ir más fácilmente.

    SOLUCIÓN

    Cambiar la forma html a esto me dio los elementos de IU que estaba buscando. La clave era entender que “class_” podría pasarse y se representaría en el código html de salida como “class”.

      
    {{ form.username(class_='form-control') }}
    {{ form.firstname(class_='form-control') }}
    {{ form.lastname(class_='form-control') }}
    {{ form.email.label }} {% for e in form.email %} {% endfor %}
    Network Address {{ form_button(url_for('main.add_email'), icon ('plus')) }}
    {{ e.network(class_='form-control') }} {{ e.address(class_='form-control') }} {{ form_button(url_for('main.remove_email', id=loop.index), icon ('remove')) }}

    Rindiendo esto: Captura de pantalla de la forma correcta.

    La respuesta fue simplemente pasar “clase_” a cada constructor de campo dentro del formulario .html.