Django中传递kwargs参数到原生PostgreSQL SQL的正确方法
问题解决:Django原生SQL动态传递标识符与参数的正确方式
错误原因
你遇到的问题本质是:cursor.execute的参数化机制是为SQL值设计的,不是为标识符(列名、JSON键名这类)设计的。当你把列名cart用参数%(field)s传递时,它会被自动加上单引号,变成字符串'cart',导致SQL语法错误——因为->>操作符需要左边是JSON类型的列,而不是字符串。
正确实现方式
区分标识符和值,分开处理
- 标识符(列名、表名等):需要用Django提供的转义方法处理后拼接进SQL,不能用参数化
- 值(JSON键、查询条件值等):可以安全地用cursor.execute的参数化传递
代码示例
from django.db import connection with connection.cursor() as cursor: # 转义列名(标识符),自动适配数据库的引号规则(PostgreSQL用双引号) escaped_field = connection.ops.quote_name('cart') # SQL中,标识符用转义后的结果,JSON键用参数化传递 query = f"SELECT sum(({escaped_field}->> %(key)s)::int) as total_price FROM core_foo;" params = { 'key': 'total_price', } cursor.execute(query, params) row = cursor.fetchone() print(row)
如果你的列名也是动态生成的(比如从变量获取),同样先转义再拼接:
dynamic_field = 'cart' # 可以是动态变量 escaped_field = connection.ops.quote_name(dynamic_field) query = f"SELECT sum(({escaped_field}->> %(key)s)::int) as total_price FROM core_foo;"
针对你的问题解答
是否需要带单/双引号?
- 对于标识符(列名、表名):不需要自己加,用
connection.ops.quote_name()会自动添加符合数据库规范的引号(比如PostgreSQL加双引号,MySQL加反引号),同时处理特殊字符转义 - 对于值(JSON键、条件值):不需要自己加,cursor.execute的参数化会自动添加引号并转义特殊字符,避免SQL注入
- 对于标识符(列名、表名):不需要自己加,用
还是不需要带单/双引号?
总结:标识符靠转义方法自动加规范引号,值靠参数化自动处理,都不需要你手动加引号。
关键提醒
永远不要直接拼接未转义的用户输入作为标识符(比如列名、表名),必须用quote_name转义,否则会存在SQL注入风险。
内容的提问来源于stack exchange,提问作者JPG
相关产品推荐
相关产品推荐

