
本文介绍在 flask 应用中安全、高效地校验表单提交的酒店名称是否已存在于 mysql 表中,避免重复插入,并指出原代码中循环逻辑错误、条件判断位置不当及潜在空值风险等问题。
本文介绍在 flask 应用中安全、高效地校验表单提交的酒店名称是否已存在于 mysql 表中,避免重复插入,并指出原代码中循环逻辑错误、条件判断位置不当及潜在空值风险等问题。
在 Flask 中处理表单提交时,常需确保新数据(如酒店名称)不与数据库中已有记录重复。原始代码试图通过 while 循环遍历查询结果并逐个比对,但存在严重逻辑缺陷:if name != names 实际是在将字符串与元组(如 ('Grand Plaza',))比较,且循环体内部嵌套了 POST 处理逻辑,导致每次迭代都重复执行表单解析和插入判断,最终仅最后一次比对生效,无法真正阻止重复插入。
正确的做法是:先一次性获取所有已存在名称,再统一判断新名称是否已存在。MySQL 查询返回的是元组列表(如 [('Grand Plaza',), ('Ocean View',)]),需提取首字段并转为纯字符串列表:
cur.execute('SELECT name FROM hotels')
existing_names = [row[0] for row in cur.fetchall()] # 推荐:直接解包,更清晰
# 或等价写法:existing_names = list(map(lambda x: x[0], cur.fetchall()))随后,在表单提交验证通过后,使用 not in 进行成员检查(而非 !=):
if request.method == 'POST':
name = request.form.get('name', '').strip()
# 其他字段同理获取...
if name and name not in existing_names: # ✅ 关键:先判空,再查重
cur.execute(
'INSERT INTO hotels (image, name, city, features, RoomCount, peakSeasonRate, OffPeakSeasonRate) '
'VALUES (%s, %s, %s, %s, %s, %s, %s)',
(image, name, city, features, RoomCount, peakSeasonRate, OffPeakSeasonRate)
)
mysql.connection.commit()
flash('酒店添加成功', 'success')
return redirect(url_for('hotelRecord'))
else:
flash('该酒店名称已存在,请勿重复提交', 'warning')⚠️ 重要注意事项:
-
避免在循环内处理 POST 请求:原代码将
if request.method == "POST"放在while内部,导致逻辑错乱;应始终先完成数据准备(如查询现有名称),再统一处理请求。 -
防御性编程:使用
request.form.get('name', '').strip()替代直接索引,防止KeyError或空格干扰;增加if name判断可拦截空白提交。 -
性能优化建议:对于大数据量场景,推荐改用 SQL 原生
INSERT ... SELECT ... WHERE NOT EXISTS或INSERT IGNORE,由数据库层保证唯一性(需提前为name字段添加UNIQUE约束)。 -
资源管理:
cur.close()应放在函数末尾或finally块中,避免因提前return导致游标未释放(当前代码中cur.close()仅在插入成功时执行,存在泄漏风险)。
综上,核心原则是:分离数据准备与业务逻辑,用集合操作替代低效循环,结合空值校验与数据库约束,构建健壮的防重机制。


















