dio 上传文件报错_Flask干货:Flask数据交换——上传文件

c5862200838f7ca6d9ab08ee8bcf11ed.png

事情是这样的。

d2e41d138e20d5133a9c45380f9c5eb7.png

有一天五号程序员打算网购一盒巧克力送给自己的女朋友

3bf1d660d3a853459ef97b77186160f2.png

想必女朋友收到礼物是这样的:

c880a791a57c3c8679f839e7709755a4.png

结果商家邮寄来的巧克力中夹着一张纸条:

55be4609a60ecf43c87ef6446429b3af.png

害!你说气不气人,现在都还没理我!

5b5fb306aa68dcd0a16a7b54efc40eba.png

这不投诉更待何时?

accc8f2a54e1d8b4ebf308d0e2a684e8.png

打开投诉界面一看,咦?要求上传图片。

1434891853e92ca98007dbad84aabfab.png

哈~既然说起上传,那咱们就先说一下如何使用Flask上传文件

一、使用Flask上传文件的简单实现

Flask文件上传比较简单,主要是下面3点:

l 一个<form>标签被标记有enctype = multipart/form-data ,并且在里面包含一个<input type=file>标签

l 服务端应用通过请求对象上的files字典访问文件

l 使用文件的save()方法将文件永久的保存在文件系统的某处

既然涉及到保存,那肯定会用到路径。下面是os.path方法的相关属性:

l os.path.sep:Windows下路径分隔符,即反斜杠 ‘’;

l os.path.altsep:Linux下路径分隔符,即斜杠‘/‘;

l 当前目录:os.path.curdir;

l 父目录:os.path.pardir;

l 绝对路径:os.path.abspath(path)

有了这些基本知识就够了,接下来直接实战。新建app.py文件,内容如下:

 from flask import Flask,render_template,request
from os import path
from werkzeug.utils import secure_filename

app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        return render_template('upload.html')
    else:
        f = request.files['file']
        filename = secure_filename(f.filename)
        f.save(path.join('D:/test', filename))
        #文件的具体路径根据个人而定,这里以D盘test文件夹为例
        return "上传文件成功!"

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

导入secure_filename方法是为了在传入中文文件名时过滤掉中文名,只留下文件名后缀;path.join()则可以整合路径。

在templates文件夹下新建upload.html文件,用于文件上传:

 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
<style type="text/css">
.div1 {
    height:180px;
    width:380px;
    border:1px solid #8A8989;
    margin:0 auto;
}
.input {
    display: block;
    width:250px;
    height:30px;
    margin:10px auto;
}
.button {
    background: #2066C5;
    color:white;
    font-size:18px;
    font-weight: bold;
    height: 30px;
    border-radius: 4px;
}
</style>
</head>
<body>
 <div class="div1">
     <form action="" method="post" enctype="multipart/form-data">
         <input type="file" name="file" class="input">
         <input type="submit" value="上传" class="input button">
     </form>
</div>
</body>
</html>

运行文件后将能看见如下界面:

385f438078db8a230fbc889452bb0728.png

选择好指定的word文件:

bce6c057fcae212230a4cb6b703e81f6.png

点击上传,显示“上传成功”:

c55bbbd2ed9282c196f73eaaa6964796.png

由于在form标签中action属性没有指定其他网页,所以会跳转到同一个网址,但此时的request.method已经由GET变为POST,所以执行else下的代码。

看一下文件夹内有没有:

c7c347a0dcb5c55a2de04784bd8524b6.png

成功!我们的电脑就像一个服务器,可以实现任意文件的上传,但是以中文命名的文件上传时会出现中文丢失

二、改进上传功能

虽然上面的代码实现了文件上传功能,但还有一些不足

l 文件没有重新命名,多名用户上传同名文件如何处理?

l 没有实现文件目录自动创建,文件保存失败怎么办?

l 文件上传时没有进行文件格式检验,影响数据安全怎么设卡?

为了解决上述问题,新建form.py文件用于表单验证:

 from wtforms import Form,FileField
from flask_wtf.file import FileRequired,FileAllowed

class UploadForm(Form):
    file = FileField(validators=[FileRequired(), FileAllowed(['jpg','png','gif'])])

其中,FileRequired()用来验证文件上传是否为空,FileAllowed()用来验证上传文件的后缀名。

然后修改app.py文件:

 from flask import Flask,render_template,request,send_from_directory
import time
import os
from os import path
from werkzeug.utils import secure_filename
from werkzeug.datastructures import CombinedMultiDict
import platform
from form import UploadForm

app = Flask(__name__)
#判断系统,使用不同分隔符
if platform.system() == "Windows":
    slash = ''
else:
    platform.system() == "Linux"
    slash = '/'
UPLOAD_PATH = 'D:' + slash + 'uploads' + slash

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        return render_template('upload.html')
    else:
        if not path.exists(UPLOAD_PATH):
            os.makedirs(UPLOAD_PATH) #路径不存在时创建路径
        form = UploadForm(CombinedMultiDict([request.form, request.files]))
        if form.validate():
            f = request.files['file']
            filename = secure_filename(f.filename)
            ext = filename.rsplit('.', 1)[1] #获取文件后缀
            unix_time = int(time.time()) #获取时间用于命名,不会重复
            new_filename = str(unix_time) + '.' + ext
            
            f.save(path.join(UPLOAD_PATH, new_filename))
            return "上传文件成功!"
        else:
            return "仅支持jpg、png和gif格式的文件!"
            
@app.route('/images/<filename>/', methods=['GET', 'POST'])
def get_image(filename):
    return send_from_directory(UPLOAD_PATH, filename)

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

其中,os.makedirs()可以自动创建文件路径,然后用CombinedMultiDict()把form和file的数据结合起来一起验证,用时间戳加文件后缀重新命名文件,最后新建get_image()视图函数用于浏览或下载文件,并用send_from_directory(dirpath, filename)函数将文件进行在线下载功能。

运行app.py,选择在桌面上的“handsome.jpg”文件:

90c0c9c1712a69957d406dec3d85fc3b.png

点击上传可以看到“文件上传成功!”。找一下电脑中的源文件:

d5c9cfcc78f1c74d020620e72a79c6d2.png

可以看到在D盘下生成了uploads文件夹,接下来在浏览器访问:

http://127.0.0.1:5000/images/xxx.jpg/,根据保存时的文件名输入网址实现在线下载功能。

如果上传word文档行不行呢?试一下:

f8c278b592001580daec7d01ef632ede.png

不行!报错!

因为上传的文件只能是三种图片格式!

看到这里有些小伙伴可能会感到熟悉,是不是在哪里见过?

没错,百度贴吧

登录百度美图吧,随机找到一张图片并打开:

0a4d747677ae1224559433754d087d61.png

观察其网址,再点开同一帖子下的图片观察其网址,你会发现其中的命名规则

今天的内容图比较多,看起来比较费劲,上传文件的内容非常重要,需要多加练习才能掌握!

下一次,我们将谈一谈经常提到的Cookies

09bc221224689f09834429136b806054.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值