Flask WTForms:为什么我上传文件的POST请求没有发送文件数据?

Kat*_*tie 5 flask wtforms flask-wtforms

我正在尝试制作一个上传文件的表单,但是文件数据未随请求发送。我正在手动导航到我的文件并点击提交。我的FileRequired验证程序失败。(如果我不包括在内,则该data字段form.scan_file为空。)

这是我的表格:

from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed, FileRequired

class ScanForm(FlaskForm):
    scan_file = FileField(validators=[FileAllowed(['nii', 'nii.gz', 'zip']), FileRequired()])
Run Code Online (Sandbox Code Playgroud)

这是我的views.py

from flask import Blueprint, render_template, request, flash, redirect, url_for, session
from .models import Scan
from .forms import ScanForm
from .service import ScanService
from cookiecutter_mbam.utils import flash_errors

blueprint = Blueprint('scan', __name__, url_prefix='/scans', static_folder='../static')

@blueprint.route('/add', methods=['GET', 'POST'])
def add():
    """Add a scan."""
    form = ScanForm(request.form)
    if form.validate_on_submit():
        f = form.scan_file.data
        service = ScanService()
        xnat_uri = service.upload(session['user_id'], session['curr_experiment'], f)
        Scan.create(xnat_uri=xnat_uri)
        flash('You successfully added a new scan.', 'success')
        return redirect(url_for('experiment.experiments'))
    else:
        flash_errors(form)
    return render_template('scans/upload.html',scan_form=form)
Run Code Online (Sandbox Code Playgroud)

这是我的upload.html

{% extends "layout.html" %}

{% block content %}


<form method="POST" action="{{ url_for('scan.add') }}" enctype="multipart/form-data">
    {{ scan_form.csrf_token }}

    <input type="file" name="file">
    <input class="btn btn-primary" type="submit" value="Submit">

</form>

{% endblock %}
Run Code Online (Sandbox Code Playgroud)

看来我犯的错误与这个人相同。我究竟做错了什么?

编辑:自发布以来,我发现了这个问题,但是在通过提供的解决方案进行工作时,似乎没有任何问题与我的情况有关。

编辑2:有一次,我在Werkzeug调试器中打印了request.files,这是一个空字典。我无法完全重建为获得该结果所做的一切。从那以后,我插入了一些打印语句,实际上,request.files有了我的文件对象。因此,我有一种方法来检索我的文件。但我应该能够在取回我的文件对象form.scan_file.data(见这里)。现在,此结果为None。更具体地说,form.scan_file.has_file()计算为Falseform.data评估为{'scan_file': None, 'csrf_token': <long-random-string> }

即使我有另一种检索文件对象的方法,此问题的结果也是验证不起作用。我的表单未通过FileRequired()验证。

编辑3:通过对问题的新理解,我发现它类似于该问题。但是,它至少显然没有重复,因为没有的 form = ScanForm(request.form)form = ScanForm()或者form = ScanForm(CombinedMultiDict((request.files, request.form)))使在编辑2所列行为的任何差异。

Din*_*har 5

首先,检查您的数据是否在该路由上发布。其次,我认为您不需要传递request.formScanForm,只需实例化它即可:

def add():
    """Add a scan."""
    form = ScanForm()
    ...
Run Code Online (Sandbox Code Playgroud)

要检查通过表单发布的内容,而不是

if form.validate_on_submit():
Run Code Online (Sandbox Code Playgroud)

您可以使用并打印form.scan_file.data

if form.is_submitted():
    print(form.scan_file.data)
Run Code Online (Sandbox Code Playgroud)

最后,您可以使用{{scan_form.scan_file}}<input type="file" name="scan_file"> (输入元素的名称属性应等于“ scan_file”)呈现输入文件。

这是我的示例:

形成:

class ArticleForm(FlaskForm):
    article_image = FileField('Article_image', validators=[FileRequired()])
Run Code Online (Sandbox Code Playgroud)

模板中的表格:

<form action="" method="post" enctype="multipart/form-data">
    {{ article_form.csrf_token }}
    {{ article_form.article_image }}
    <input type="submit" value="submit"/>
</form>
Run Code Online (Sandbox Code Playgroud)

控制器(保存文件):

article_form = ArticleForm()

        if article_form.validate_on_submit():

            f = article_form.article_image.data
            name = current_user.username + "__" + f.filename
            name = secure_filename(name)
            f.save(os.path.join("./static/article_images/", name))
Run Code Online (Sandbox Code Playgroud)