自定义SQLAlchemy查询中如何将列表作为JSON数组绑定参数
SQLAlchemy 传入列表生成MySQL JSON_ARRAY的实现方法
不需要退回到手动拼接字符串的方式,通过原生text()方法即可安全实现,手动拼接字符串存在SQL注入、特殊字符转义失败的风险,完全不推荐使用。
你遇到的(1241, 'Operand should contain 1 column(s)')报错,本质是SQLAlchemy默认对传入的列表参数采用IN子句的展开逻辑,但没有被正确识别到合法的展开上下文,才会被解析为多列参数。以下是两种可直接运行的实现方案:
方案1:绑定JSON类型自动序列化(最推荐)
利用SQLAlchemy内置的JSON类型处理器,驱动会自动将Python列表序列化为标准JSON格式字符串传入MySQL,不需要在SQL中调用JSON_ARRAY()函数,兼容性和安全性最高:
from sqlalchemy import text, JSON # 为elements参数指定JSON类型绑定 query = text( "INSERT into models (name, elements) VALUES (:model_name, :elements)" ).bindparams(elements=JSON) # 直接传入Python原生列表即可,无需手动转字符串 session.execute(query, {"model_name": "foo", "elements": ["bar", "baz"]}) session.commit()
该方案会自动处理列表元素中的引号、转义符等特殊字符,完全规避注入风险。
方案2:配合MySQL JSON_ARRAY函数展开参数
如果你需要在数据库侧通过JSON_ARRAY()函数构造数组值,只需要给列表参数加上expanding=True标记,SQLAlchemy就会自动将列表展开为对应数量的占位符,匹配JSON_ARRAY()的多参数要求:
from sqlalchemy import text, bindparam # 标记elements为可展开参数,最终会生成JSON_ARRAY(%s, %s)的合法SQL结构 query = text( "INSERT into models (name, elements) VALUES (:model_name, JSON_ARRAY(:elements))" ).bindparams( bindparam("elements", expanding=True) ) session.execute(query, {"model_name": "foo", "elements": ["bar", "baz"]}) session.commit()
你之前直接包裹JSON_ARRAY()没有生效,就是因为没有加expanding=True标记,SQLAlchemy不会自动展开列表,导致参数数量不匹配。
注意:禁止使用字符串拼接的方式构造参数,一旦列表元素包含引号、斜杠等特殊字符,会直接导致SQL语法错误,同时存在SQL注入漏洞。
内容的提问来源于stack exchange,提问作者LoicM
相关产品推荐
相关产品推荐

