Flask前端提交后数据无法写入PostgreSQL数据库如何解决?
Flask + PostgreSQL 数据持久化问题排查与解决
问题背景
使用Flask开发应用,PostgreSQL作为数据库,编写了插入数据的接口,执行commit()后数据仍未存入数据库,需解决该持久化问题。
原代码展示
Flask后端代码
conn = psycopg2.connect(database="postgres", user="root", host='localhost', password="dbpass", port=5432) cur = conn.cursor() @app.route('/') def index(): return render_template('index.html') @app.route('/shift/', methods=('GET', 'POST')) def shift(): if request.method == 'POST': id = request.form['id'] if not id: flash('ID is required!') else: t = datetime.now().hour day = datetime.now().date().isoformat() shift = 2 if 8 <= t <=14: shift = 1 cur.execute("INSERT INTO shift (date, employee_id, shift_number) values (%s, %s, %s)", (day, id, shift)) conn.commit() return redirect(url_for('index')) return render_template('shift.html')
前端表单代码
<form action="" method="post"> <label for="title">Log your shift</label> <br> <input type="text" name="id" placeholder="Enter work id" value="{{ request.form.id}}"></input> <br> <button type=”submit”> Submit </button> </form>
问题排查
- 前端表单提交失效:按钮的
type属性使用了中文引号(”submit”),浏览器无法正确识别,导致表单无法触发POST请求。 - 插入逻辑不完整:仅当时间在8-14点时才执行插入语句,其他时段(
shift=2)完全没有执行插入操作,自然无数据存入。 - 全局数据库连接线程不安全:Flask默认多线程运行,全局的
conn和cur会被多个请求共享,导致事务混乱、连接状态异常,最终数据无法持久化。 - 无异常捕获机制:即使插入过程中出现错误(如表结构不匹配、字段类型错误),也无法得知问题所在,无法及时回滚或排查。
修复方案
1. 修复前端表单
将按钮的中文引号替换为英文引号,确保表单能正常提交:
<form action="" method="post"> <label for="title">Log your shift</label> <br> <input type="text" name="id" placeholder="Enter work id" value="{{ request.form.id }}"> <br> <button type="submit"> Submit </button> </form>
2. 重构后端数据库操作逻辑
使用请求级别的数据库连接,完善插入逻辑并添加异常处理:
from flask import Flask, render_template, request, redirect, url_for, flash import psycopg2 from datetime import datetime app = Flask(__name__) app.secret_key = 'your-custom-secret-key' # 启用flash消息需配置密钥 # 封装数据库连接方法,每个请求创建独立连接 def get_db_connection(): conn = psycopg2.connect( database="postgres", user="root", host='localhost', password="dbpass", port=5432 ) return conn @app.route('/') def index(): return render_template('index.html') @app.route('/shift/', methods=('GET', 'POST')) def shift(): if request.method == 'POST': # 使用get方法避免ID未提交时抛出KeyError emp_id = request.form.get('id') if not emp_id: flash('ID是必填项!') # 返回表单页,保留用户输入内容 return redirect(url_for('shift')) t = datetime.now().hour day = datetime.now().date().isoformat() shift_num = 2 if 8 <= t <= 14: shift_num = 1 try: # 每次请求创建新连接 conn = get_db_connection() cur = conn.cursor() # 无论时段都执行插入 cur.execute( "INSERT INTO shift (date, employee_id, shift_number) VALUES (%s, %s, %s)", (day, emp_id, shift_num) ) conn.commit() flash('班次记录成功!') except Exception as e: # 出错时回滚事务 conn.rollback() flash(f'记录失败:{str(e)}') # 打印错误日志便于排查 print(f"数据库操作错误:{e}") finally: # 确保连接关闭,避免资源泄漏 if cur: cur.close() if conn: conn.close() return redirect(url_for('index')) return render_template('shift.html')
关键修复说明
- 表单提交修复:替换中文引号,保证表单能正常触发POST请求。
- 插入逻辑完善:无论时段是1还是2,都执行插入操作,覆盖所有场景。
- 线程安全的数据库连接:每个请求创建独立的数据库连接,避免多线程下的连接冲突。
- 异常处理:捕获数据库操作异常,执行回滚并提示用户,同时记录错误日志便于排查。
- 用户体验优化:ID为空时返回表单页,保留用户输入,添加操作结果提示。
内容的提问来源于stack exchange,提问作者shinny.dogma
相关产品推荐
相关产品推荐

