添加过滤器以使用pyscopg2

时间:2019-05-28 22:03:33

标签: python sql psycopg2

尝试创建动态过滤器时,我很难在不带引号的情况下打印where语句。

输出:select "col1", "col2" from "table1" where "col2=1234" and "col3=column1"

所需:select "col1", "col2" from "table1" where col2="1234" and col3="column1"

def filter(table,*args,**kwarg):
 query = sql.SQL("select {0} from {1} where {2}").format(
    sql.SQL(', ').join(map(sql.Identifier,[arg for arg in args])),
    sql.Identifier(table),
    sql.SQL(' and ').join(map(sql.Identifier,{(str(k)+'='+str(v)) for k,v in kwarg.iteritems()}))
    )
 print query.as_string(Connection())

1 个答案:

答案 0 :(得分:1)

您正在将每个条件编码为单个SQL标识符-即,您实际上是在编码sql.Identifier('foo=bar')

另一个陷阱是您将查询值直接放在SQL中。尽管您可以相信来源, 一般来说,这将是一个坏主意。更好的是使用占位符,并提供实际值 在执行时。

最后-列表理解通常比map更受推荐;不过,这是一种样式选择。

将它们放在一起,谓词将使用以下类似内容正确呈现:

def filter(table, *args, **kwargs):
  conditions = [sql.SQL(' = ').join([sql.Identifier(k), sql.Placeholder()]) for k in kwarg.keys()]
  query = sql.SQL("select {0} from {1} where {2}").format(
     sql.SQL(', ').join([sql.Identifier(arg) for arg in args]),
     sql.Identifier(table),
     sql.SQL(' and ').join(conditions)
  )

这确实假定在查询构造和执行之间未修改基础dict。您的“执行”类似于:

cursor.execute(sql, kwargs.values())

如果该假设不成立,请在sql.Placeholder()理解中将sql.Literal(v)替换为conditions,并使用kwargs.items()代替kwargs.keys()。在这种情况下,我认为 Literal可以正确地转义几乎所有有风险的字符串,但使用占位符和参数更安全。

希望有帮助