PostgreSQL中含空格字符串作为SQL变量的.format()用法问题
在PostgreSQL中处理含空格字符串变量的SQL查询问题
问题场景
我使用.format()方法拼接SQL查询时,遇到含空格的字符串变量触发语法错误,代码如下:
data = "something with white space" choice = "DESC" limit = 10 def rDB(sql_request): with connection.cursor() as cursor: cursor.execute(sql_request) row = cursor.fetchall() return row def queryWithFormat(data, choice, limit): return(''' SELECT col1, SUM(col2) as nb FROM Table WHERE col1 = {d} GROUP BY col1 ORDER BY nb {c} LIMIT {l} '''.format(d=data, c=choice, l=limit)) rDB(queryWithFormat(data, choice, limit))
报错信息
django.db.utils.ProgrammingError: ERROR: syntax error on or near 'with'
LINE 8: WHERE col1 = something with white ...
-------------------------------^
我尝试了一种解决方案,但不确定是否合规:
- 拆分SQL请求
- 使用
.format()处理排序方向("DESC"/"ASC") - 使用
%s处理含空格的字符串
对应代码:
def requeteDB(sql_request): with connection.cursor() as cursor: cursor.execute(*sql_request) row = cursor.fetchall() return row def queryWithFormat(data, choice, limit): return(''' SELECT col1, SUM(col2) as nb FROM Table WHERE col1 = %s GROUP BY col1 ORDER BY nb {0} LIMIT %s '''.format(choice), [data,limit])
希望确认该方案是否合规,或获取正确的实现方式。
方案验证与正确实践
你尝试的方案合规性说明
你用%s做参数绑定、.format()处理排序方向的思路是合规且安全的,但有两个细节需要优化:
- 排序方向(
DESC/ASC)属于SQL语法关键字,用.format()时必须做合法性校验,避免SQL注入风险 - 可以调整写法更贴合Django的参数化查询规范
优化后的正确实现
方式1:原生SQL参数化查询(推荐)
利用Django cursor的参数绑定能力,同时对排序方向做白名单校验:
data = "something with white space" choice = "DESC" limit = 10 def rDB(): # 校验排序方向合法性,只允许ASC/DESC if choice not in ("ASC", "DESC"): raise ValueError("无效的排序方向,仅支持ASC或DESC") with connection.cursor() as cursor: # %s作为参数占位符,参数列表传入execute第二个参数 cursor.execute(''' SELECT col1, SUM(col2) as nb FROM "Table" WHERE col1 = %s GROUP BY col1 ORDER BY nb {} LIMIT %s '''.format(choice), [data, limit]) row = cursor.fetchall() return row rDB()
方式2:使用Django ORM(更推荐)
如果业务允许,用ORM替代原生SQL能大幅提升安全性和可维护性:
from django.db.models import Sum data = "something with white space" choice = "DESC" limit = 10 # 校验排序方向 if choice not in ("ASC", "DESC"): raise ValueError("无效的排序方向") # ORM实现等价查询 result = ( Table.objects.filter(col1=data) .values("col1") .annotate(nb=Sum("col2")) .order_by("-nb" if choice == "DESC" else "nb") .values_list("col1", "nb") [:limit] )
核心注意事项
- 禁止用
.format()直接拼接用户输入的字符串参数:既会引发含空格字符串的语法错误,还存在严重的SQL注入风险 - SQL关键字(如排序方向)用
.format()时必须做白名单校验:只允许预设的合法值,杜绝注入可能 - 数值类型参数(如limit):优先用参数绑定,保持写法统一
内容的提问来源于stack exchange,提问作者problème0123
相关产品推荐
相关产品推荐

