I have a form that collects some information, and a form that allows the user to upload a file. These both work. Now I'm trying to make a form that combines them and inherits from both.
My file upload form has a FileRequired() validator. This passes fine when I am accessing just the upload form. If I have my combined form try to inherit the upload form, validation fails. However, if I remove the FileRequired() validator, either by removing it from the form it inherits from, or by replacing that field on the combination form, the file uploads fine. It is only validation that is failing, not the file upload. I can validate by other means (checking the length of request.files.getlist('<file>'), and in fact am already checking that to prevent the user from uploading too many files, so I have a workaround, but I'd like to understand why this is failing.
Here is my views.py:
def add_scan(request, exp_id):
"""Add a scan"""
user_id = str(current_user.get_id())
if len(request.files.getlist('scan_file')) > 3:
flash('You can upload up to three files.', 'warning')
return redirect(url_for('scan.add'))
for f in request.files.getlist('scan_file'):
ScanService(user_id, exp_id).add(f)
flash('You successfully added a new scan.', 'success')
return redirect(url_for('experiment.experiments'))
@blueprint.route('/add', methods=['GET', 'POST'])
def add():
"""Access the add scan route and form."""
form = ScanForm()
if form.validate_on_submit():
exp_id = str(session['curr_experiment'])
return add_scan(request, exp_id)
else:
flash_errors(form)
return render_template('scans/upload.html',scan_form=form)
@blueprint.route('/add_experiment_and_scans', methods=['GET', 'POST'])
def add_experiment_and_scans():
"""Acess the add experiment and scans route and form"""
form = ExperimentAndScanForm(request.form)
if form.validate_on_submit():
exp_id = add_experiment(form)
return add_scan(request, exp_id)
else:
flash_errors(form)
return render_template('scans/experiment_and_scans.html', experiment_and_scan_form=form)
Here are the forms:
class ExperimentForm(FlaskForm):
"""Experiment form."""
date = DateField('Date')
scanner = SelectField('Scanner', choices=[('GE', 'GE'), ('Sie', 'Siemens'), ('Phi', 'Phillips')])
field_strength = SelectField('FieldStrength', choices=[('1.5T', '1.5T'), ('3T', '3T'), ('7T', '7T')])
def __init__(self, *args, **kwargs):
"""Create instance."""
super(ExperimentForm, self).__init__(*args, **kwargs)
class ScanForm(FlaskForm):
scan_file = FileField(validators=[FileAllowed(['nii', 'nii.gz', 'zip']), FileRequired()])
submit = SubmitField('Submit')
def __init__(self, *args, **kwargs):
"""Create instance."""
super(ScanForm, self).__init__(*args, **kwargs)
class ExperimentAndScanForm(ExperimentForm, ScanForm):
def __init__(self, *args, **kwargs):
"""Create instance."""
super(ExperimentAndScanForm, self).__init__(*args, **kwargs)
Validation succeeds for ScanForm but fails FileRequired() with ExperimentAndScanForm. Removing FileRequired() from ExperimentAndScanForm (either by removing it from ScanForm or replacing the scan_file property in ExperimentAndScanForm) allows file upload. Making a new scan_file property in ExperimentAndScanForm with FileRequired() causes validation to fail.
I'm not sure whether it's helpful, but here's the template that renders this form:
<form method="POST" action="{{ url_for('scan.add_experiment_and_scans') }}" enctype="multipart/form-data">
<div class="form-group">
{{experiment_and_scan_form.date.label}}
{{experiment_and_scan_form.date(placeholder="Date of session", class_="form-control")}}
</div>
<div class="form-group">
{{experiment_and_scan_form.scanner.label}}
{{experiment_and_scan_form.scanner(placeholder="Scanner", class_="form-control")}}
</div>
<div class="form-group">
{{experiment_and_scan_form.field_strength.label}}
{{experiment_and_scan_form.field_strength(placeholder="Field Strength", class_="form-control")}}
</div>
{{ experiment_and_scan_form.csrf_token }}
{{ experiment_and_scan_form.hidden_tag() }}
{{ experiment_and_scan_form.scan_file(multiple="multiple") }}
{{ experiment_and_scan_form.submit }}
</form>