SQLAlchemy中位置(无命名)参数的使用方法及报错排查
SQLAlchemy使用位置(无命名)参数的正确方案
报错根因
你碰到的AttributeError: 'list' object has no attribute 'keys'错误,根本原因是SQLAlchemy从1.4版本开始重构了参数校验逻辑:用text()包裹的原生SQL,默认会把第二位置传入的参数识别为「键值对格式的参数字典」。你直接把数字1当参数传进去,底层代码想从这个参数里读字典键名,自然就报错了。
具体实现方式
- SQLAlchemy 2.0+ 原生位置占位支持
新版本专门为习惯无命名传参的用户开放了适配开关,只要在构造text()语句时加上positional=True参数,就可以直接在SQL里用?做占位符,按原生逻辑传位置参数:import sqlalchemy from sqlalchemy import text engine = sqlalchemy.create_engine('mysql://py:123@localhost/py', echo=True) con = engine.connect() # 开启positional模式后,直接用?占位,按顺序传参即可 res = con.execute( text("select uid, name from users where uid = ?", positional=True), 1 ) - 低版本(1.4及更早)兼容方案
旧版本没有专门的位置参数开关,想用无命名的效果,最省心的方式是直接用纯数字当占位符名——完全不需要给每个参数起有意义的变量名,只要占位符的数字顺序和你传值的顺序对应,写出来的SQL和原生位置参数没有任何区别:# 用纯数字作为占位符标识,按位置传对应的值 res = con.execute( text("select uid, name from users where uid = :0"), {"0": 1} ) # 多个参数时直接按顺序填数字占位即可 res = con.execute( text("select uid, name from users where uid = :0 and name = :1"), {"0": 1, "1": "test"} ) - 追求完全原生无ORM层绑定的写法时,可以直接从引擎拿原生DBAPI连接,这层完全兼容原生位置传参逻辑,不受SQLAlchemy参数校验规则限制:
raw_con = engine.raw_connection() cursor = raw_con.cursor() # 原生连接直接支持?占位的位置传参 cursor.execute("select uid, name from users where uid = ?", (1,))
注意:所有参数传递不要省略元组/列表包裹,哪怕只有一个参数,原生DBAPI规范里位置参数都需要按可迭代格式传入,避免触发类型校验错误。
内容的提问来源于stack exchange,提问作者XTF
相关产品推荐
相关产品推荐

