【问题标题】:Flask WTForms: Why is my POST request to upload a file not sending the file data?Flask WTForms:为什么我上传文件的 POST 请求没有发送文件数据?
【发布时间】:2019-03-24 17:48:56
【问题描述】:

我正在尝试制作一个表单来上传文件,但文件数据没有随请求一起发送。我手动导航到我的文件并点击提交。我的 FileRequired 验证器失败。 (如果我不包含它,form.scan_file 上的 data 字段为空。)

这是我的表格:

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()])

这是我的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)

这是我的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 %}

看起来我犯的错误与this person 不同。我究竟做错了什么?

编辑:自发布以来,我找到了this question,但在解决所提供的解决方案时,似乎与我的情况无关。

编辑 2:有一次,我在 Werkzeug 调试器中打印了 request.files,它是一个空字典。我无法准确重建我为获得该结果所做的工作。从那时起,我插入了一些打印语句,事实上,request.files 有我的文件对象。所以我有办法检索我的文件。但我应该能够在form.scan_file.data 检索我的文件对象(参见here)。现在这评估为None。更具体地说,form.scan_file.has_file() 的计算结果为 Falseform.data 计算结果为 {'scan_file': None, 'csrf_token': &lt;long-random-string&gt; }

即使我有另一种方法来检索我的文件对象,这个问题的后果是验证不起作用。我的表单没有通过 FileRequired() 验证。

编辑 3:根据我对问题的新理解,我发现它类似于 question。但是,它至少显然不是重复的,因为 form = ScanForm(request.form)form = ScanForm()form = ScanForm(CombinedMultiDict((request.files, request.form))) 都不会对编辑 2 中概述的行为产生任何影响。

【问题讨论】:

  • request.files['file']
  • type="file" name="file" enctype="multipart/form-data"
  • @Swift request.files 为空。 @Attack68 我尝试按照您的建议更改输入元素,但没有任何区别。
  • @Swift 我确定我做的不对,因为它不起作用。我已经看过该教程(和其他教程),但我仍然不清楚如何。我在路由中实例化类对象(如果你指的是表单对象)。您概述了这两种可能性很有帮助,下面的 Dinko 也指出了这一点:我认为客户端没有发送文件。不确定检查的最佳方法,但在开发工具的网络窗格中,无论我刷新页面还是尝试添加文件,添加请求的大小都是相同的。那么是什么让客户端不发送呢?我现在需要完成 Dinko 的解决方案。

标签: flask flask-wtforms wtforms


【解决方案1】:

首先,检查您的数据是否在该路线上发布。其次,我认为你不需要将request.form 传递给ScanForm,你只需要像这样实例化它:

def add():
    """Add a scan."""
    form = ScanForm()
    ...

使用表单检查发布的内容,而不是

if form.validate_on_submit():

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

if form.is_submitted():
    print(form.scan_file.data)

最后,您可以使用 {{scan_form.scan_file }}&lt;input type="file" name="scan_file"&gt; (输入元素的name属性应该等于"scan_file")

这是我的例子:

表格:

class ArticleForm(FlaskForm):
    article_image = FileField('Article_image', validators=[FileRequired()])

模板中的表格:

<form action="" method="post" enctype="multipart/form-data">
    {{ article_form.csrf_token }}
    {{ article_form.article_image }}
    <input type="submit" value="submit"/>
</form>

控制器(保存文件):

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))

【讨论】:

  • 嗨丁科。你完全正确,我应该在 3 小时前就知道这一点。这段时间我并不是有意无视你的回答。我实际上试图解决它,出于某种原因{{scan_form.scan_file }} 第一次尝试它只是导致文件字段根本不呈现。但是现在我无法重现它,并且它工作正常,并且在 ScanForm() 的参数中不包含任何内容。我会投票并接受你的回答。谢谢!
  • 终于可以评论xd了。也许模板没有正确渲染。在烧瓶中使用调试模式或将 TEMPLATES_AUTO_RELOAD = True 放入 app.config 。此外,即使进行了更改,有时也会从缓存中使用静态文件。为此,请使用hard refresh
  • 很好的建议@DinkoPehar - if form.csvfile.data != None: 就像一个魅力
  • 我在 2 年前写了这篇文章,所以我不得不花时间记住我在这里回答的内容。我很高兴我帮助了你:D
猜你喜欢
  • 1970-01-01
  • 2021-11-16
  • 1970-01-01
  • 1970-01-01
  • 2021-08-10
  • 1970-01-01
  • 2019-01-13
  • 2019-10-16
  • 2016-04-08
相关资源
最近更新 更多