如何用Flask处理文件上传的问题

338 阅读7分钟

如何用Flask处理文件上传

Flask是一个用Python构建的轻量级或微型Web框架,有助于创建Web应用程序。它提供了有用的工具和功能,使构建网络应用更容易。Flask是可扩展的,在开始使用之前不强制要求特定的结构或要求复杂的模板代码。它为开发者提供了灵活性。

简介

网络应用程序的一个重要特征是能够让用户上传文件。这些文件可以是图片、PDF、音频CSV等。在这篇文章中,我们将看看如何设置一个基本的flask应用,让用户上传文件。

前提条件

通过本指南,我们假设读者具有Python编程语言、HTML的基本知识,并且他们必须具有flask的基本知识;尽管本指南对初学者友好。

在本指南中,我们将使用Python 3和VS Code文本编辑器,你可以下载vscodePython

目标

我们将建立一个flask应用程序,使用户能够上传文件到服务器。在本指南的最后,读者将熟悉。

  • 创建一个虚拟环境
  • 激活一个虚拟环境
  • 设置一个flask应用
  • 启用文件上传

Python 虚拟环境

虚拟环境是Python项目的一个孤立的环境。有一个由Python创建的叫做venv的模块,它给开发者提供了一个独特的环境,能够安装所有对特定项目来说是独一无二的软件包。

虚拟环境并不改变系统中默认的Python版本或默认安装的软件包,相反,它让你不受系统中安装的其他软件包的干扰。这使得在任何计算机上运行任何Python项目都很容易,而不管系统中安装的Python版本或包是什么。

如何创建一个虚拟环境

创建虚拟环境的过程根据操作系统的不同而不同。在本指南中,我们将从windows操作系统的角度来看这个过程。

首先,在Windows设备上打开PowerShell,使用下面的命令建立一个目录。

mkdir

使用cd directory-name 进入新目录,然后使用命令安装虚拟环境。

pip install virtualenv

然后使用命令创建虚拟环境。

virtualenv myenv

注意,myenv 是我的虚拟环境的名称,它可以是你希望的任何名称。接下来,用命令激活虚拟环境。

myenv/Scripts/activate

如果你使用的是命令行界面(CMD),你的命令将如下所示。

myenv\Scripts\activate.bat

创建我们的项目

在激活了我们的虚拟环境之后,我们现在可以创建我们的项目。要做到这一点,我们将为该项目创建一个新的目录。

使用下面的命令。

mkdir tutorial

注意:tutorial 是我项目的名称。你可以给你的项目起任何你喜欢的名字。要建立一个flask应用程序,我们必须首先安装flask。

要做到这一点,我们将使用下面的命令。

pip install flask 

安装完成后,我们将创建一个新文件,名称为app.py ,用下面的代码更新该文件。

from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():
    return"hello world"

if __name__==('__main__'):
    app.run(debug=True)

从上面的代码中,我们正在从我们安装的flask库中导入flask。

@app.route 是为我们做路由的。

index() 是我们的视图函数,它将把我们的页面内容返回给浏览器。

if语句返回app.run ,这将使我们能够运行我们的应用程序,然后在我们保存更改时刷新我们的页面。为了运行我们的应用程序,我们在终端上运行下面的命令。

python app.py

请注意,app.py 是我的应用程序的名称,你的名称可能不同。如果一切顺利,你将得到如下所示的结果。

App running

为了上传文件,我们将使用WTformsflask-uploads 库。为了使用这些库,我们需要安装它们。

用下面的命令来做。

pip install flask_wtf, WTForms
pip install flask-uploads

安装完成后,我们将创建一个文件字段,将代码更新为以下代码。

from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import FileField

app = Flask(__name__)

class MyForm(FlaskForm):
    image = FileField('image')

@app.route('/')
def index():
    form = MyForm()
    return render_template('index.html')

if __name__==('__main__'):
    app.run(debug=True)

从上面的代码中,我们首先从flask_wtf 中导入FlaskForm ,从wtforms 中导入FileField 。接下来,我们为我们的表单创建了一个类,因为Myform image是我们的图像文件将被保存到的文件字段。我们在index function 中调用我们的Form类。我们把我们的render 改为render template

这也是一个用于渲染HTML模板的flask库。从代码中我们渲染了index.html 。当我们在Flask中使用render_template时,我们创建了一个叫做templates的文件夹,在那里我们存储HTML文件。现在让我们在templates文件夹中创建我们要渲染的HTML模板。

用下面的代码更新HTML文件。

!doctype html>
<html>
  <head>
    <title>File Upload</title>
  </head>
  <body>

    <form action="/" method="POST" enctype="multipart/form-data">
        {{ form.csrf_token }}
        {{ form.image }}
        <button type="submit">upload</button>
    </form>
  </body>
</html>

从上面的代码来看,我们的表单需要一个方法POST ,因为我们将发布一个文件。csrf_token 是一个内置的函数,为我们处理安全问题,然后我们使用form.image ,调用我们在Form Class 中创建的表单字段。现在我们可以使用python app.py 来运行我们的应用程序。如果一切都正确,你会得到一个运行时错误,就像下面的图片一样。

RuntimeError

只要你试图使用csrf_token ,而不在你的项目文件中添加secret_key ,就会出现这个错误。让我们在我们的代码中添加一个secret key

将你的代码更新为下面的代码。

from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import FileField

app = Flask(__name__)

app.config['SECRET_KEY'] = 'mysecretkey'

class MyForm(FlaskForm):
    image = FileField('image')

@app.route('/')
def index():
    form = MyForm()
    return render_template('index.html')

if __name__==('__main__'):
    app.run(debug=True)

secret_key 可以是任何你想要的东西。

让我们把我们的代码更新为下面的代码。

from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import FileField

app = Flask(__name__)

app.config['SECRET_KEY'] = 'mysecretkey'

class MyForm(FlaskForm):
    image = FileField('image')

@app.route('/')
def index():
    form = MyForm()
    return render_template('index.html', form = form)

if __name__==('__main__'):
    app.run(debug=True)

我们的页面现在应该看起来像下面的图片。

App running

从上面的代码来看,form=form ,这样我们的表单就可以显示在我们的HTML页面上。如果我们试图上传图片,我们会遇到另一个错误,如下图所示。

Method Not Allowed

当我们没有给我们的route 指定一个方法时,这个错误经常被抛出。为了解决这个问题,我们将在我们的路由中添加下面的代码。

@app.route('/', methods=['GET', 'POST'])

添加上述代码后,我们的上传将工作,但它不会被保存,因为我们没有给它一个保存的路径。这就是flask uploads 的作用。

让我们使用命令导入flask-uploads

from flask_uploads import configure_uploads, IMAGES, UploadSet

configure_uploads 使我们能够设置图片的保存路径, 是我们要上传的文件类型。IMAGES

我们将更新我们的代码:app.config['UPLOADED_IMAGES_DEST'] = 'uploads/images ,这将设置图片保存的文件路径,images = UploadSet('images', IMAGES)configure_uploads(app, images) 保存文件扩展名并配置上传。

if form.validate_on_submit():
        filename = images.save(form.image.data)
        return f'Filename: {filename}'
    return render_template('index.html', form = form)

上述片段将验证并保存我们的图像文件。

我们的最终代码将看起来像下面这样。

from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import FileField
from flask_uploads import configure_uploads, IMAGES, UploadSet

app = Flask(__name__)

app.config['SECRET_KEY'] = 'thisisasecret'
app.config['UPLOADED_IMAGES_DEST'] = 'uploads/images'

images = UploadSet('images', IMAGES)
configure_uploads(app, images)


class MyForm(FlaskForm):
    image = FileField('image')

@app.route('/', methods=['GET', 'POST'])
def index():
    form = MyForm()
    if form.validate_on_submit():
        filename = images.save(form.image.data)
        return f'Filename: {filename}'
    return render_template('index.html', form = form)

if __name__==('__main__'):
    app.run(debug=True)

上传文件后,文件名将被返回,如下图所示。

File Uploaded

结论

现在我们可以上传图片了。要上传其他类型的文件,我们需要做的就是通过flask上传导入它们,配置它们的目标路径,并指定它们的文件扩展。