1、Flask上傳文件
上傳文件步驟:
1. 在模版html中,表單需要指定 enctype='multipart/form-data' 才能上傳文件。
2. 在后臺(tái)如果想要獲取上傳的文件,那么應(yīng)該使用 request.files.get('文件名') 來(lái)獲取。
3. 保存文件之前,先要使用 werkzeug.utils.secure_filename 來(lái)對(duì)上傳上來(lái)的文件名進(jìn)行一個(gè)過(guò)濾。能保證不會(huì)有安全問(wèn)題。
4. 獲取到上傳上來(lái)的文件后,使用 文件對(duì)象.save(路徑) 方法來(lái)保存文件。路徑=完整路徑=路徑名+文件名
示例代碼:
main.py
from flask import Flask, render_template, request
from werkzeug.utils import secure_filename
import os
app = Flask(__name__)
UPLOAD_PATH = os.path.join(os.path.dirname(__file__), 'images')
@app.route('/')
def index():
return 'Hello! '
@app.route('/upload/', methods=['GET', 'POST'])
def upload():
if request.method == 'GET':
return render_template('upload.html')
else:
img_file = request.files.get('pic')
file_name = img_file.filename
# 文件名的安全轉(zhuǎn)換
filename = secure_filename(file_name)
# 保存文件
img_file.save(os.path.join(UPLOAD_PATH, filename))
return '上傳文件成功!'
if __name__ == '__main__':
app.run(debug=True)
upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="/upload/" method="post" enctype="multipart/form-data">
上傳文件:<input type="file" name="pic"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
運(yùn)行結(jié)果:
系統(tǒng)路徑中生成的文件:
2、Flask下載文件
2.1 send_from_directory方法
從服務(wù)器上讀取文件,應(yīng)該定義一個(gè)url與視圖函數(shù),來(lái)獲取指定的文件。
在這個(gè)視圖函數(shù)中,使用 send_from_directory(文件的目錄,文件名) 來(lái)獲取。
send_from_direction函數(shù)底層實(shí)現(xiàn):
def send_from_directory(directory, filename, **options):
"""Send a file from a given directory with :func:`send_file`. This
is a secure way to quickly expose static files from an upload folder
or something similar.
Example usage::
@app.route('/uploads/<path:filename>')
def download_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'],
filename, as_attachment=True)
.. admonition:: Sending files and Performance
It is strongly recommended to activate either ``X-Sendfile`` support in
your webserver or (if no authentication happens) to tell the webserver
to serve files for the given path on its own without calling into the
web application for improved performance.
.. versionadded:: 0.5
:param directory: the directory where all the files are stored.
:param filename: the filename relative to that directory to
download.
:param options: optional keyword arguments that are directly
forwarded to :func:`send_file`.
"""
filename = fspath(filename)
directory = fspath(directory)
filename = safe_join(directory, filename)
if not os.path.isabs(filename):
filename = os.path.join(current_app.root_path, filename)
try:
if not os.path.isfile(filename):
raise NotFound()
except (TypeError, ValueError):
raise BadRequest()
options.setdefault("conditional", True)
return send_file(filename, **options)
示例代碼:
目前服務(wù)器中存在的文件:
from flask import Flask, send_from_directory
import os
app = Flask(__name__)
UPLOAD_PATH = os.path.join(os.path.dirname(__file__), 'images')
@app.route('/download/<string:filename>/')
def download_file(filename):
return send_from_directory(UPLOAD_PATH, filename)
# return send_from_directory(UPLOAD_PATH, filename, as_attachment=True)
if __name__ == '__main__':
app.run(debug=True)
運(yùn)行結(jié)果:
當(dāng)參數(shù)as_attachment=True時(shí):
2.2 send_file方法
send_file()函數(shù):
def send_file(
path_or_file: t.Union[os.PathLike, str, t.BinaryIO],
mimetype: t.Optional[str] = None,
as_attachment: bool = False,
download_name: t.Optional[str] = None,
attachment_filename: t.Optional[str] = None,
conditional: bool = True,
etag: t.Union[bool, str] = True,
add_etags: t.Optional[bool] = None,
last_modified: t.Optional[t.Union[datetime, int, float]] = None,
max_age: t.Optional[
t.Union[int, t.Callable[[t.Optional[str]], t.Optional[int]]]
] = None,
cache_timeout: t.Optional[int] = None,
):
參數(shù)解析:
- path_or_file:要發(fā)送的文件的路徑,如果給出了相對(duì)路徑,則相對(duì)于當(dāng)前工作目錄?;蛘撸远M(jìn)制模式打開的類文件對(duì)象。確保將文件指針查找到數(shù)據(jù)的開頭。
- mimetype:為文件發(fā)送的MIME類型。如果沒有提供,它將嘗試從文件名檢測(cè)它。
- as_attachment:指示瀏覽器應(yīng)該提供給保存文件而不是顯示它。
- download_name:瀏覽器保存文件時(shí)使用的默認(rèn)名稱。默認(rèn)為傳遞的文件名。
- conditional:基于請(qǐng)求頭啟用條件響應(yīng)和范圍響應(yīng)。需要傳遞一個(gè)文件路徑和``environ``。
- etag:計(jì)算文件的etag,這需要傳遞一個(gè)文件路徑。也可以是字符串來(lái)代替。
- last_modified:發(fā)送文件的最后修改時(shí)間,單位為秒。如果沒有提供,它將嘗試從文件路徑檢測(cè)它。
- max_age:客戶端應(yīng)該緩存文件多長(zhǎng)時(shí)間,以秒為單位。如果設(shè)置,' ' Cache-Control ' '將為' ' public ' ',否則將為' ' no-cache ' '以選擇條件緩存。
注意:
示例代碼:
import os
from flask import Flask, send_file, request, render_template, redirect
from werkzeug.utils import secure_filename
app = Flask(__name__)
UPLOAD_FOLDER = 'media' # 注意:要提前在根目錄下新建media文件,否則會(huì)報(bào)錯(cuò)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
# 判斷上傳的文件是否是允許的后綴
def allowed_file(filename):
return "." in filename and filename.rsplit('.', 1)[1].lower() in set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
@app.route('/')
def index():
return "hello world!"
@app.route('/generate_file')
def generate_file():
with open('./new_file.txt', 'w', encoding='utf-8') as f:
f.write('我是new_file.txt文件!')
return "<./new_file.txt>文件已經(jīng)生成!"
@app.route('/download')
def download():
return send_file('./new_file.txt', as_attachment=True)
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'GET':
return render_template('upload.html')
else:
if "file" not in request.files:
return redirect(request.url)
file = request.files.get('file') # 獲取文件
# 上傳空文件(無(wú)文件)
if file.filename == '':
return redirect(request.url)
if file and allowed_file(file.filename):
if not os.path.exists(f'./templates/{UPLOAD_FOLDER}'):
os.mkdir(f'./templates/{UPLOAD_FOLDER}')
filename = secure_filename(file.filename) # 用這個(gè)函數(shù)確定文件名稱是否是安全 (注意:中文不能識(shí)別)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) # 保存文件
return "上傳文件成功!"
if __name__ == '__main__':
app.run()
下載和上傳路徑中可以添加用戶身份驗(yàn)證:
import os
from flask import Flask, send_file, request, render_template, redirect
from werkzeug.utils import secure_filename
app = Flask(__name__)
UPLOAD_FOLDER = 'media' # 注意:要提前在根目錄下新建media文件,否則會(huì)報(bào)錯(cuò)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
allow_users = ['dgw', 'super_user']
# 判斷上傳的文件是否是允許的后綴
def allowed_file(filename):
return "." in filename and filename.rsplit('.', 1)[1].lower() in set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
@app.route('/')
def index():
return "hello world!"
@app.route('/generate_file')
def generate_file():
with open('./new_file.txt', 'w', encoding='utf-8') as f:
f.write('我是new_file.txt文件!')
return "<./new_file.txt>文件已經(jīng)生成!"
@app.route('/download')
def download():
user_name = request.args.get('user_name')
if not user_name:
return "你沒有權(quán)限下載文件!"
if user_name and user_name not in allow_users:
return "你沒有權(quán)限下載文件!"
return send_file('./new_file.txt', as_attachment=True)
@app.route('/upload/<string:user_name>', methods=['GET', 'POST'])
def upload(user_name):
if request.method == 'GET':
if user_name not in allow_users:
return "您沒有權(quán)限訪問(wèn)此頁(yè)面!"
return render_template('upload.html')
else:
if user_name not in allow_users:
return "您沒有權(quán)限訪問(wèn)此頁(yè)面!"
if "file" not in request.files:
return redirect(request.url)
file = request.files.get('file') # 獲取文件
# 上傳空文件(無(wú)文件)
if file.filename == '':
return redirect(request.url)
if file and allowed_file(file.filename):
if not os.path.exists(f'./templates/{UPLOAD_FOLDER}'):
os.mkdir(f'./templates/{UPLOAD_FOLDER}')
filename = secure_filename(file.filename) # 用這個(gè)函數(shù)確定文件名稱是否是安全 (注意:中文不能識(shí)別)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) # 保存文件
return "上傳文件成功!"
if __name__ == '__main__':
app.run()
upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Upload</title>
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="上傳">
</form>
</body>
</html>
3、Flask-wtf驗(yàn)證上傳的文件
關(guān)鍵點(diǎn):
- 定義驗(yàn)證表單類的時(shí)候,對(duì)文件類型的字段,需要采用 FileField 這個(gè)類型,即wtforms.FileField
- 驗(yàn)證器需要從 flask_wtf.file 中導(dǎo)入。 flask_wtf.file.FileRequired 和 flask_wtf.file.FileAllowed
- flask_wtf.file.FileRequired 是用來(lái)驗(yàn)證文件上傳不能為空。
- flask_wtf.file.FileAllowed 用來(lái)驗(yàn)證上傳的文件的后綴名, 如常見圖片后綴 .jpg 和.png以及.gif等。
- 在視圖函數(shù)中,需要使用 from werkzeug.datastructures import CombinedMultiDict 來(lái)把request.form 與 request.files 來(lái)進(jìn)行合并。
- 最后使用 表單驗(yàn)證對(duì)象.validate()進(jìn)行驗(yàn)證。
示例代碼:
main.py
from flask import Flask, render_template, request
from werkzeug.datastructures import CombinedMultiDict
from werkzeug.utils import secure_filename
import os
from formcheck import UpLoadForm
app = Flask(__name__)
UPLOAD_PATH = os.path.join(os.path.dirname(__file__), 'images')
@app.route('/upload/', methods=['GET', 'POST'])
def upload():
if request.method == 'GET':
return render_template('upload.html')
else:
form = UpLoadForm(CombinedMultiDict([request.form, request.files]))
if form.validate():
img_file = form.pic.data
file_name = secure_filename(img_file.filename)
img_file.save(os.path.join(UPLOAD_PATH, file_name))
return '上傳文件成功!'
else:
return f'{form.errors}'
if __name__ == '__main__':
app.run(debug=True)
formcheck.py
from wtforms import Form, FileField
from flask_wtf.file import FileAllowed, FileRequired
class UpLoadForm(Form):
pic = FileField(validators=[FileRequired(), FileAllowed(['jpg', 'png', 'gif'])])
upload.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="/upload/" method="post" enctype="multipart/form-data">
上傳文件:<input type="file" name="pic"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
運(yùn)行結(jié)果:
參考博文:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-787238.html
Python Flask 文件下載_flask下載_liyinchi1988的博客-CSDN博客文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-787238.html
到了這里,關(guān)于Flask框架上傳和下載文件的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!