使用列表参数执行Django Raw SQL Query失败,报错参数未完全转换
解决Django raw SQL中IN子句的参数格式化错误
你的错误not all arguments converted during string formatting核心原因是:Django的raw()方法没办法直接把整个列表作为单个参数匹配%s占位符。SQL的IN子句需要和列表长度一致的占位符数量,而你当前的写法会把整个list当成一个参数传入,导致参数数量不匹配。
下面提供两种可行的解决方法:
方法1:动态生成对应数量的占位符
这是适配所有数据库的通用写法,通过动态生成和列表长度一致的%s占位符,让每个列表元素对应一个SQL参数:
# 根据列表长度生成对应数量的占位符字符串 placeholders = ', '.join(['%s'] * len(list)) products = Product.objects.raw( f'''SELECT DISTINCT ON(I.product_id) P.id, P.name, P.desc, C.name AS ram, I.image FROM products_product AS P LEFT JOIN categories AS RPC ON P.id = RPC.product_id LEFT JOIN company AS CP ON P.company_id = CP.id LEFT JOIN category AS C ON RPC.category_id = C.id LEFT JOIN image AS I ON I.product_id = P.id WHERE P.id IN ({placeholders})''', list )
这种写法完全通用,而且通过Django的参数传递机制避免了SQL注入风险——占位符只是动态生成数量,实际参数还是安全传入的。
方法2:利用PostgreSQL的数组语法(如果使用PostgreSQL)
如果你的项目用的是PostgreSQL数据库,可以用更简洁的ANY语法直接传入整个列表作为单个参数:
products = Product.objects.raw( '''SELECT DISTINCT ON(I.product_id) P.id, P.name, P.desc, C.name AS ram, I.image FROM products_product AS P LEFT JOIN categories AS RPC ON P.id = RPC.product_id LEFT JOIN company AS CP ON P.company_id = CP.id LEFT JOIN category AS C ON RPC.category_id = C.id LEFT JOIN image AS I ON I.product_id = P.id WHERE P.id = ANY(%s)''', [list] )
这里要注意参数是[list],把整个列表包装成一个元素传入,PostgreSQL会自动处理数组和IN子句的匹配逻辑。
内容的提问来源于stack exchange,提问作者user3541631
相关产品推荐
相关产品推荐

