Flask上传文件到服务器目录并存路径到数据库报错如何解决
问题原因
代码报错是多个基础写法错误叠加导致的:
- 缩进不符合Python语法规则:模型类的
__repr__方法没有缩进在类体内,路由函数create()里除了前两行POST判断的代码,剩下的文件保存、数据库操作代码全部缩进到了函数外部,脱离请求上下文访问request对象会直接报错。 - 取值逻辑错误:文件上传控件的内容存储在
request.files中,用request.form取文件字段只能拿到空值;且数据库需要存储的是文件最终落盘的完整路径,不是表单的空字段值。 - 类名不匹配:定义的数据库模型类名为
some_to_db,实例化写入数据时用的类名是Article,会直接触发NameError找不到对应类。 - 缺少前置校验:没有判断用户是否上传文件、上传目录是否存在、文件名是否合法,空值写入设置了
nullable=False的数据库字段会直接触发约束报错。 - 裸
except捕获所有异常会吞掉真实报错信息,调试阶段无法定位具体问题。
修复方案
- 修正所有代码缩进,确保类方法、路由内的逻辑都在对应代码块的缩进层级里
- 统一模型类名,实例化时和定义的类名保持一致
- 废弃用
request.form取文件字段的写法,文件全部从request.files获取,文件保存完成后拼接好完整存储路径,再写入数据库 - 增加基础上传校验:判断文件是否存在、文件名非空,提前创建好上传目录避免保存时报错
- 调试阶段不要用裸except,打印具体异常信息方便排查问题,数据库操作失败时记得回滚会话
修正后代码
后端Flask代码
import os from datetime import datetime from flask import Flask, request, redirect, render_template from flask_sqlalchemy import SQLAlchemy from werkzeug.utils import secure_filename app = Flask(__name__) # 替换为实际的数据库连接地址 app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 替换为服务器上实际的文件存储目录绝对路径 app.config['UPLOAD_FOLDER'] = '/var/www/upload_files' # 自动创建上传目录,已存在则不报错 os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) db = SQLAlchemy(app) # 统一模型类名,前后保持一致即可 class Article(db.Model): id = db.Column(db.Integer, primary_key=True) file = db.Column(db.String(300), nullable=False) file1 = db.Column(db.String(300), nullable=False) date = db.Column(db.DateTime, default=datetime.utcnow) # __repr__ 必须缩进在类内部 def __repr__(self): return '<Article %r>' % self.id @app.route("/create", methods=['POST', 'GET']) def create(): if request.method == "POST": # 校验两个文件字段都存在 if 'file' not in request.files or 'file1' not in request.files: return "请选择所有需要上传的文件" f = request.files['file'] g = request.files['file1'] # 校验文件名非空,避免用户未选文件就提交 if f.filename == '' or g.filename == '': return "请选择有效上传文件" # 安全处理文件名,拼接完整保存路径后存储文件 f_save_path = os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(f.filename)) f.save(f_save_path) g_save_path = os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(g.filename)) g.save(g_save_path) # 把文件实际存储路径写入数据库 article = Article(file=f_save_path, file1=g_save_path) try: db.session.add(article) db.session.commit() return redirect('/admin') except Exception as e: db.session.rollback() # 调试阶段返回具体错误信息,生产环境请替换为友好提示 return f"写入数据库报错: {str(e)}" # GET请求直接返回上传表单页面 return render_template('create.html', title="UPLOAD") if __name__ == '__main__': with app.app_context(): # 首次运行自动建表,表已存在可注释该行 db.create_all() app.run(debug=True)
HTML表单代码(原表单逻辑无问题,仅给按钮补充type="submit"兼容不同浏览器)
<form class="form-contact" method="post" enctype="multipart/form-data"> <p><label>Some file 1</label><input type="file" name="file"/></p> <p><label>Some file 2</label><input type="file" name="file1"/></p> <button class="pushable" type="submit"> <span class="shadow"></span> <span class="edge"></span> <span class="front"> Submit </span> </button> </form>
额外注意事项
- 生产环境请关闭debug模式,不要把内部报错信息暴露给普通用户
- 如果允许上传同名文件,建议给文件名拼接UUID等随机前缀,避免新文件覆盖旧文件
- 给上传目录配置正确的读写权限,确保Flask运行进程有权限写入文件
内容的提问来源于stack exchange,提问作者Guvanch Akmammedov
相关产品推荐
相关产品推荐

