You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask中WTForms SelectField取值插入MySQL时SQL语法错误问题

解决Flask+WTForms中SelectField获取表名导致SQL语法错误的问题

嘿,这个问题我之前踩过坑!咱们先拆解一下错误原因:

你用参数化查询的%s占位符来处理表名,但MySQL的参数化机制是专门用来处理字段值的,不是表名、列名这种数据库标识符。当你把main_dishes传进去当表名时,它会被自动套上单引号,最终SQL变成了:

INSERT INTO 'main_dishes'(name,ingredients,price) VALUES('Salmon', ' duude,frv ', '35')

而SQL语法里,表名不能用单引号包裹(要用反引号或者直接写),这就导致了1064语法错误。

解决方案:白名单校验+表名字符串格式化

直接拼接表名有SQL注入风险,所以咱们先做白名单校验,确保用户选择的表名是你预设的合法值,再用字符串格式化把表名拼进SQL,字段值依然用参数化查询保证安全。

修改后的代码如下:

class MenuForm(Form):
    menu_type = SelectField('Menu Type', [validators.DataRequired()], 
                           choices=[('appetizers','Appetizer'),('main_dishes','Main Dish'),('desserts','Dessert'),('drinks','Drinks')], 
                           coerce=str)
    name = StringField('Name', [validators.Length(min=1, max=2000)])
    ingredients = TextAreaField('Ingredients', [validators.Length(min=10)])
    price = DecimalField('Price (Manat)', [validators.DataRequired()])

@app.route('/add_menu', methods=['GET','POST'])
@is_logged_in
def add_menu():
    form = MenuForm(request.form)
    # 定义合法表名白名单,和SelectField的选项一一对应
    valid_menu_tables = {'appetizers', 'main_dishes', 'desserts', 'drinks'}
    
    if request.method == 'POST' and form.validate():
        menu_type = form.menu_type.data
        
        # 第一步:校验表名是否在白名单内,防止SQL注入
        if menu_type not in valid_menu_tables:
            flash('Invalid menu category!', 'danger')
            return redirect(url_for('add_menu'))
            
        name = form.name.data
        ingredients = form.ingredients.data
        price = form.price.data
        
        # 创建游标
        cur = mysql.connection.cursor()
        # 表名用f-string格式化(加反引号避免特殊字符冲突),值用参数化占位符
        cur.execute(f"INSERT INTO `{menu_type}`(name, ingredients, price) VALUES(%s, %s, %s)", 
                   (name, ingredients, price))
        
        # 提交并关闭连接
        mysql.connection.commit()
        cur.close()
        
        flash('Menu is Added', 'success')
        return redirect(url_for('dashboard'))
        
    return render_template('add_menu.html', form=form)

关键要点说明:

  • 白名单校验:虽然用户是通过SelectField选择的选项,但恶意请求可能篡改menu_type的值,白名单能直接拦截非法输入,彻底杜绝SQL注入风险。
  • 表名用反引号包裹:如果你的表名包含特殊字符或MySQL关键字,反引号可以避免语法错误,即使没有特殊字符,加上也更稳妥。
  • 字段值仍用参数化:菜品名称、配料这些用户输入的内容,还是用%s占位符,既防止SQL注入,又能正确处理包含单引号等特殊字符的内容。

内容的提问来源于stack exchange,提问作者BAT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:51:38