我正在使用Flask(Python3.4)编写Web应用程序。 psycopg2连接到postgres 9.4数据库。
我可以在我的网络应用程序中选择用户可以编写自己的查询并使用网络应用程序执行它,并在html表中获取输出作为响应。
我将光标用作 conn.cursor(cursor_factory = psycopg2.extras.DictCursor) 我无法改变,因为它也被Web应用程序的其他部分使用。
我的一位用户写了如下的SQL,
SELECT
name || ' - ' || address,
id,
salary || '; ' || id from company;
psycopg2输出(错误):
?column? id ?column?
text integer (4) text
500.55; 1 1 500.55; 1
500.55; 2 2 500.55; 2
500.55; 3 3 500.55; 3
500.55; 4 4 500.55; 4
999.99; 5 5 999.99; 5
这里我得到的结果是错误的,因为重复键/字段名称?列?第二次出现覆盖第一次。
预期产出为:
?column? id ?column?
text integer (4) text
AAA - XY 1 500.55; 1
BBB - ZZ 2 500.55; 2
ABC - YY 3 500.55; 3
ABC - CC 4 500.55; 4
ABC - DD 5 999.99; 5
发送响应的服务器端代码:
# Fetch the column info
if cur.description is not None:
colinfo = [desc for desc in cur.description]
# Any rows?
if cur.rowcount > 0:
result = []
try:
for row in cur:
result.append(dict(row))
except psycopg2.ProgrammingError:
result = None
# response for html table
return Response(
response=json.dumps(colinfo, result),
status=status,
mimetype="text/json"
)
请建议,如何通过最少的代码更改来解决此问题?
与此同时,我也提出了psycopg2的问题, https://github.com/psycopg/psycopg2/issues/454
答案 0 :(得分:2)
基本问题是字典条目必须具有唯一键。如果将有多个具有相同名称的列,则不能将列名用作键。但是你可以检查一下,如果有一个重复的列名,请以某种方式使其唯一:
# Fetch the column info
if cur.description is not None:
colinfo = [desc for desc in cur.description]
# Any rows?
if cur.rowcount > 0:
result = []
rowdict = {}
colnames = [desc[0] for desc in cur.description]
try:
for row in cur:
rowdict = {}
for x in range(0, len(row)):
# make sure column name is unique, if not append index number
if colnames[x] in rowdict:
rowdict[colnames[x] + "_" + str(x)] = row[x]
else:
rowdict[colnames[x]] = row[x]
result.append(rowdict)
except psycopg2.ProgrammingError:
result = None
# response for html table
return Response(
response=json.dumps(colinfo, result),
status=status,
mimetype="text/json"
)
根据您在客户端执行的操作,您可能还必须更新colinfo以反映所做的任何列名更改。另一种选择是,如果存在重复的列名,则返回明确的错误消息,以便用户可以控制他们返回的列名。
这最终是psycopg2中的一个错误,但它只返回postgres在这种情况下为列名提供的内容。目前尚不清楚它应该做什么。
我假设您已经考虑并处理了与从客户端执行SQL相关的严重信息安全风险。我不是在试图说教,但这是一个公共论坛,如果没有其他人想要做这样的话,我就会失职。