本文详解如何在flask应用中正确提取html多行表单数据(避免重复提交与行数错乱),使用request.form.getlist()配合executemany()高效、准确地将每行独立数据批量写入sql server数据库。
本文详解如何在flask应用中正确提取html多行表单数据(避免重复提交与行数错乱),使用request.form.getlist()配合executemany()高效、准确地将每行独立数据批量写入sql server数据库。
在Web表单中动态渲染HTML表格(如编辑物料清单)时,一个常见陷阱是:所有输入字段使用相同name属性(如name="BOLno")但未做区分,导致后端仅能通过request.form['key']取到第一个值,且循环逻辑错误引发“重复插入首行”和“行数膨胀”问题。根本原因在于:HTML中同名表单控件在提交时会以键值对形式扁平化提交,而标准request.form字典只保留最后一个同名字段的值。
✅ 正确做法是:为每列使用统一的name(如name="BOLno"),并在后端用request.form.getlist()按字段名批量提取全部同名输入值组成的列表,再通过zip()横向组装成每行元组。
以下是修正后的Flask路由代码(关键修改已加注释):
from flask import request, render_template
import pyodbc as odbc # 推荐使用pyodbc替代已弃用的pypyodbc或旧odbc
@views.route('/edit/<bol>', methods=['POST', 'GET'])
def editbol(bol):
conn_str = 'DRIVER={ODBC Driver 17 for SQL Server};SERVER=xxxxxx;DATABASE=xxxxxxx;UID=xxxxxxx;PWD=xxxxxxx;'
if request.method == 'GET':
with odbc.connect(conn_str) as sql_conn:
csr = sql_conn.cursor()
csr.execute("SELECT BOLno, SERLTQTY, SERLTNUM, ITEMDESC, WEIGHT FROM BOL_VIEW WHERE bolno = ?", bol)
data = csr.fetchall()
return render_template('edit.html', data=data, BOLno=bol)
elif request.method == 'POST':
# ✅ 正确提取:每个字段名对应一个完整值列表(长度=HTML行数)
bolnos = request.form.getlist('BOLno')
serltqtys = request.form.getlist('SERLTQTY')
serltnums = request.form.getlist('SERLTNUM')
itemdescs = request.form.getlist('ITEMDESC')
weights = request.form.getlist('WEIGHT')
# ✅ 安全组装:zip自动截断至最短列表长度,防止空值错位
formdata = list(zip(bolnos, serltqtys, serltnums, itemdescs, weights))
# ✅ 高效插入:一次executemany完成全部行,避免N次commit开销
with odbc.connect(conn_str) as sql_conn:
csr = sql_conn.cursor()
csr.executemany(
"INSERT INTO BOL_HIST_Rev2 (BOLno, SERLTQTY, SERLTNUM, ITEMDESC, WEIGHT) VALUES (?, ?, ?, ?, ?)",
formdata
)
sql_conn.commit() # execumany不自动commit,需显式调用
return f'<h1>{bol} 已成功插入 {len(formdata)} 条记录</h1>'? 关键注意事项:
立即学习“Python免费学习笔记(深入)”;
- HTML模板必须保持同名列名一致:确保每个的name属性严格匹配后端getlist()中的键名(注意大小写和拼写,如SERLTNUM而非SERLTQTY);
- 前端需校验非空:getlist()返回空列表时zip()结果为空,但若某列缺失(如用户删了某行输入框),会导致行数据错位——建议前端用JavaScript动态增删行时同步管理name;
- SQL注入防护:本方案使用参数化查询(?占位符),完全规避SQL注入风险;切勿拼接字符串(如f"WHERE bolno = {bol}");
- 事务与连接管理:使用with语句自动关闭连接,避免连接泄漏;executemany()后必须commit();
- 调试技巧:开发期可打印print(len(bolnos), len(serltqtys))验证各列长度是否一致,快速定位前端渲染异常。
通过此方法,您将彻底解决“插入5行却只有4行数据”“所有行内容相同”等典型问题,实现HTML表格到数据库的精准、健壮、高性能映射。











