SQLAlchemy ORM如何实现带绑定参数的select where参数化查询
SQLAlchemy ORM 参数绑定实现方法
当前写法的实际表现
你现在写的条件逻辑:
sql = select(User).where(User.first_name == 'Tester').where(User.age == 18)
本身已经是安全的参数化查询:SQLAlchemy不会把硬编码的值直接拼接到SQL语句中,底层会自动根据数据库驱动生成对应占位符,把值单独作为参数传给驱动,不存在SQL注入风险。你可以把引擎的echo参数设为True,就能看到实际生成的SQL是带占位符、参数单独传递的。
这种写法的唯一限制是参数值在构造查询语句时就固定了,没法实现你要的「构造语句时只留占位符,调用execute()时再传实际参数」的效果。
等效Adonis参数绑定的ORM实现
SQLAlchemy 2.0版本的ORM原生支持执行阶段传参的写法,不需要切换到Core语法,用内置的bindparam()构造命名占位符即可,代码示例如下:
from sqlalchemy import create_engine, select, bindparam from sqlalchemy.orm import Session # 导入提前定义好的User模型 from models import User engine = create_engine("postgresql+psycopg2://test:test@localhost:5432/test", echo=False, future=True) session = Session(engine) # 构造查询时只定义占位符,不写入实际值 stmt = select(User).where( User.first_name == bindparam("query_name"), User.age == bindparam("query_age") ) # 执行查询时再传入实际参数,和Adonis传参逻辑完全一致 result = session.execute( stmt, params={"query_name": "Tester", "query_age": 18} ) # 获取匹配的单条用户记录 user = result.scalar_one_or_none()
关键注意点
- 不需要手动写
?这类位置占位符,SQLAlchemy会自动适配你使用的数据库驱动,转换成对应格式的占位符(比如PostgreSQL+psycopg2会转成%s,SQLite会转成?),你只需要用命名占位符即可,不需要关心驱动差异 - 这种写法和写死值的写法,底层生成的SQL、执行效率、返回结果格式完全一致,唯一区别是参数传入时机从语句构造阶段移到了执行阶段,适合需要复用同一条查询语句、动态传参的场景
- 不要为了实现参数绑定去拼接原生SQL字符串,
bindparam()可以和所有ORM字段条件配合使用,返回的依然是ORM模型实例,完全符合纯ORM写法要求 - 禁止直接把用户输入的字符串通过f-string、字符串拼接的方式写入where条件,只要用SQLAlchemy的条件表达式、
bindparam()传参,就会自动做参数转义,避免SQL注入风险
内容的提问来源于stack exchange,提问作者Just Me
相关产品推荐
相关产品推荐

