Django从QuerySet获取SQL参数无引号无法执行如何解决
问题核心原因
str(qs.query) 本质是Django提供的调试用方法,不会对参数做类型适配、转义和加引号处理,生成的语句本来就不是设计用来直接执行的,因此会出现日期、字符串等类型参数缺失引号的语法错误。
最优解决方案:参数绑定执行(推荐)
不需要自己拼接带引号的SQL,直接利用pandas支持的参数绑定特性,既能避免语法错误,还能防止SQL注入,步骤如下:
- 从QuerySet中拆分出SQL模板和参数列表
sql, params = qs.query.sql_with_params()
- 适配SQL Server的参数占位符:Django默认生成的占位符是
%s,pyodbc要求用?,做一次替换即可
# 替换占位符 sql = sql.replace('%s', '?')
- 直接传入参数调用pandas查询
df = pd.read_sql_query(sql, conn, params=params)
可选方案:生成带引号的完整可执行SQL
如果确实需要拿到完整的、可直接运行的SQL字符串,可以用Django数据库连接的游标方法自动转义参数:
from django.db import connection sql, params = qs.query.sql_with_params() with connection.cursor() as cursor: # 自动处理参数转义、加引号,返回字节串转成字符串即可 full_executable_sql = cursor.mogrify(sql, params).decode('utf-8')
生成的full_executable_sql就是语法合法的SQL语句,可以直接执行。
额外性能优化提示
如果不想额外维护pyodbc连接,也可以尝试Django原生的优化方式:
- 用
qs.values()/qs.values_list()代替默认的模型实例加载,避免实例化开销,5万行数据的查询耗时通常可以降到和pyodbc接近的水平 - 处理超大数据量时搭配
iterator()方法减少内存占用
内容的提问来源于stack exchange,提问作者Shubham Periwal
相关产品推荐
相关产品推荐

