I have created dynamic fields using WTForms FieldList, macros and Javascript.
Using this code to validate many fields (StringField, SelectField etc) I can add many fields dynamically, and they validate and update my Sqlite3 database.
However I want to be able to add files dynamically now.
The standard Flask-WTF code for file uploads looks like this:
How can I utilisie this for validation on a FieldList form?
if form.validate_on_submit():
f_fileA = form.inputname.data
filename_fileA = secure_filename(f_fileA.filename)
f_fileA.save(os.path.join(
UPLOAD_FOLDER, filename_fileA
))
My code
Forms
forms.py
class ChildForm(Form):
childAinput_1 = StringField(
'ChildA input 1'
)
childAinput_2 = IntegerField(
'ChildA input 2'
)
category = SelectField(
'Category',
choices=[('cat1', 'Category 1'), ('cat2', 'Category 2')]
)
fileA = FileField(
'FileA'
)
class MainForm(FlaskForm):
parentinput_1 = StringField(
'Parent input 1'
)
parentinput_2 = StringField(
'Parent input 2'
)
childrenA = FieldList(
FormField(ChildForm),
min_entries=1,
max_entries=20
)
My HTML template with form fields
form.html template
<a id="add" href="#">Add ChildA</a>
{# Show all subforms #}
<form id="childA-form" action="" method="POST" role="form">
{{ form.hidden_tag() }}
{# show parents fields #}
<div>
{{ form.parentinput_1.label }}
{{ form.parentinput_1 }}
</div>
<div>
{{ form.parentinput_2.label }}
{{ form.parentinput_2 }}
</div>
<div id="subforms-container">
{% for subform in form.childrenA %}
{{ macros.render_childA_form(subform, loop.index0) }}
{% endfor %}
</div>
<button type="submit">Send</button>
</form>
{% if form.errors %}
{{ form.errors }}
{% endif %}
{# Form template #}
{{ macros.render_childA_form(_template, '_') }}
Current form validation (without adding in file upload yet)
routes.py
@bp.route('/', methods=['GET', 'POST'])
def index():
form = MainForm()
template_form = ChildForm(prefix='childrenA-_-')
if form.validate_on_submit():
# Create parent
new_parent = Parent(
parentinput_1 = form.parentinput_1.data,
parentinput_2 = form.parentinput_2.data
)
db.session.add(new_parent)
for childAe in form.childrenA.data:
new_childA = ChildA(**childAe)
# Add to parent
new_parent.childrenA.append(new_childA)
db.session.commit()
return render_template(
'index.html',
form=form,
_template=template_form
)
And the macros if it’s useful:
macros.html
{%- macro render_childA_form(subform, index) %}
<div id="childA-{{ index }}-form" class="{% if index != '_' %}subform{% else %}is-hidden{% endif %}" data-index="{{ index }}">
<div>
{{ subform.childAinput_1.label }}
{{ subform.childAinput_1 }}
</div>
<div>
{{ subform.childAinput_2.label }}
{{ subform.childAinput_2}}
</div>
<div>
{{ subform.category.label }}
{{ subform.category }}
</div>
<div>
{{ subform.fileA.label }}
{{ subform.fileA }}
</div>
<a class="remove" href="#">Remove</a>
<hr/>
</div>
{%- endmacro %}
My models
models.py
class Parent(db.Model):
"""Stores parents."""
__tablename__ = 'parents'
parentinput_1 = db.Column(db.String(100))
parentinput_2 = db.Column(db.String(100))
id = db.Column(db.Integer, primary_key=True)
class ChildA(db.Model):
"""Stores childrenA of a parent."""
__tablename__ = 'childrenA'
id = db.Column(db.Integer, primary_key=True)
parent_id = db.Column(db.Integer, db.ForeignKey('parents.id'))
childAinput_1 = db.Column(db.String(100))
childAinput_2 = db.Column(db.Integer)
category = db.Column(db.String(4))
fileA = db.Column(db.String(255))
# Relationship
parent = db.relationship(
'Parent',
backref=db.backref('childrenA', lazy='dynamic', collection_class=list)
)
(The models, routes and forms are actually in one file, but I split them in the question for ease of reading)
Thank you very much