在Django中调用SQL Server存储过程时nvarchar转datetime出错
Django调用SQL Server存储过程传递datetime值报错问题
报错信息
执行代码时触发类型转换错误:
django.db.utils.ProgrammingError: ('42000', '[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Error converting data type nvarchar to datetime. (8114) (SQLExecDirectW)')
直接拼接datetime变量时,出现语法错误:
django.db.utils.ProgrammingError: ('42000', "[42000] [Microsoft][SQL Server Native Client 11.0][SQL Server]Incorrect syntax near '-'. (102) (SQLExecDirectW)")
直接传递datetime对象则抛出类型错误:
TypeError: can only concatenate str (not "datetime.datetime") to str
问题代码
最初的实现代码:
fromDate = datetime(2022, 1, 1) toDate = datetime(2022, 12, 31) dealershipId = request.GET['dealershipId'] cursor = connection.cursor() cursor.execute(f"EXEC proc_LoadJobCardbyDateRange [@Fromdate={fromDate}, @Todate={toDate}, @DealershipId={dealershipId}]") result = cursor.fetchall()
尝试的另一种写法:
cursor.execute("EXEC proc_LoadJobCardbyDateRange @Fromdate="+fromDate+", @Todate='2022-12-31 00:00:00', @DealershipId="+dealershipId)
错误原因
- 类型拼接错误:直接用
+拼接datetime对象和字符串,会触发类型不兼容错误;即使转成字符串,拼接后SQL语句中的日期未加单引号,会被SQL解析成减法运算(如2022-1-1),引发语法错误。 - 参数格式与语法错误:用f-string传递datetime时,Python默认的字符串格式不符合SQL Server的datetime解析要求,且存储过程调用时错误地用方括号包裹参数列表,导致SQL解析失败。
- 未使用参数化查询:手动拼接/格式化SQL语句,既存在SQL注入风险,又无法让Django自动完成Python类型到SQL Server数据类型的转换,引发类型转换报错。
正确解决方法
使用Django数据库游标的参数化查询,这是官方推荐的安全传参方式,能自动处理类型转换,同时避免SQL注入。
方法1:标准参数化写法
fromDate = datetime(2022, 1, 1) toDate = datetime(2022, 12, 31) dealershipId = request.GET['dealershipId'] cursor = connection.cursor() # 用%s作为占位符,第二个参数传入参数列表 cursor.execute( "EXEC proc_LoadJobCardbyDateRange @Fromdate=%s, @Todate=%s, @DealershipId=%s", [fromDate, toDate, dealershipId] ) result = cursor.fetchall()
方法2:适配SQL Server的pyodbc占位符写法
如果上述方式不生效,可使用pyodbc的?占位符:
cursor.execute( "EXEC proc_LoadJobCardbyDateRange @Fromdate=?, @Todate=?, @DealershipId=?", (fromDate, toDate, dealershipId) )
关键注意事项
- 禁止手动拼接SQL语句:无论是f-string还是
+拼接,都会带来安全风险和类型问题。 - 参数化查询自动处理类型转换:Django会自动将Python的
datetime对象转换成SQL Server可识别的datetime类型,无需手动转字符串。 - 存储过程调用语法:参数列表不需要用方括号包裹,直接使用
@参数名=占位符格式即可。
内容的提问来源于stack exchange,提问作者Maisum
相关产品推荐
相关产品推荐

