Flask中request.files无法获取文件部分,请求排查上传失败原因
我来帮你排查这个文件上传失败的问题,核心问题出在HTML表单的配置上,另外Python代码里也有几个需要调整的地方,一步步来看:
1. HTML表单的enctype属性位置错误
你现在把enctype="multipart/form-data"写在了<input type="file">标签里,但这个属性必须放在<form>标签上——浏览器只有识别到form标签的这个属性,才会正确编码并发送文件数据。如果form没有配置这个属性,Flask的request.files就无法获取到上传的文件,自然会触发"No file part"的提示。
修改后的HTML代码:
{% extends "layout.html" %} {% block title %} Picture {% endblock %} {% block main %} <form action="/picture" method="post" enctype="multipart/form-data"> <div> <p>Profile picture (32mb max).</p> <input type="file" id="picture" name="picture"> <input type="submit" value="Upload"> </div> </form> {% endblock %}
2. Python代码里的几个潜在问题
除了HTML的问题,你的Python代码还有几个需要修正的点,否则即使表单正确了,上传也可能失败:
问题A:错误地提前读取了文件内容
你调用了file = request.files["picture"].read(),这会把文件内容一次性读进内存,但之后再访问file.filename就会失效——因为read()操作会把FileStorage对象的指针移到文件末尾,此时变量file已经变成了字节流,不再是原来的FileStorage对象,自然没有filename属性。
应该先获取文件名和验证,再处理文件保存。
问题B:文件保存路径可能不正确
os.path.join("/static", filename)是绝对路径,在不同环境下可能找不到对应的目录,建议用Flask应用的根目录来拼接相对路径,避免环境差异导致的路径错误。
问题C:返回值错误
最后return print(filename)只会在控制台打印文件名,用户浏览器会得到一个空响应,应该重定向到某个页面(比如个人资料页)或者渲染模板,给用户明确的反馈。
修改后的Python代码示例:
import sqlite3 import traceback import sys import os from flask import Blueprint, render_template, redirect, session, request, flash from application import profileName, uploadPicture, profilePicture, allowed_file from werkzeug.utils import secure_filename # Set Blueprints picture = Blueprint('picture', __name__,) @picture.route("/picture", methods=["GET", "POST"]) def pictureFunction(): # 先检查用户是否登录(根据你的session逻辑调整) if "user_id" not in session: flash("Please log in first") return redirect("/login") if request.method == "POST": # check if the post request has the file part if "picture" not in request.files: flash("No file part") return redirect("/picture") file = request.files["picture"] # if user does not select file, browser also submit a empty part without filename if file.filename == "": flash("No selected file") return redirect("/picture") # Check if all conditions are satisfied if file and allowed_file(file.filename): filename = secure_filename(file.filename) # 用Flask蓝图的根目录拼接静态文件路径,避免绝对路径问题 upload_path = os.path.join(picture.root_path, "static", filename) file.save(upload_path) # 这里可以调用你的uploadPicture函数把文件名存到数据库 # uploadPicture(session["user_id"], filename) flash("Profile picture uploaded successfully!") return redirect("/profile") # 重定向到个人资料页或者其他页面 # GET请求时渲染上传页面 return render_template("picture.html")
额外检查点
- 确认你的
allowed_file函数正确判断了.jpg等允许的文件扩展名,比如:def allowed_file(filename): ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'} return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS - 确保
static目录存在,并且有写入权限,否则保存文件时会抛出权限错误。
内容的提问来源于stack exchange,提问作者Benoît

