您如何将列名称干净地传递到游标中,Python/SQLite?
How do you cleanly pass column names into cursor, Python/SQLite?
我是游标的新手,我正在尝试通过使用针对 sqlite3:[=12= 的清理方法构建动态 python sql 插入语句来练习]
import sqlite3
conn = sqlite3.connect("db.sqlite")
cursor = conn.cursor()
list = ['column1', 'column2', 'column3', 'value1', 'value2', 'value3']
cursor.execute("""insert into table_name (?,?,?)
values (?,?,?)""", list)
当我尝试使用它时,在值所在的行出现语法错误 "sqlite3.OperationalError: near "?""。尽管事实上当我对列进行硬编码(并从列表中删除列名)时,我没有问题。我可以用 %s 构建,但我知道首选经过消毒的方法。
如何干净地插入这些?还是我遗漏了一些明显的东西?
首先,我将从创建列和值的映射开始:
data = {'column1': 'value1', 'column2': 'value2', 'column3': 'value3'}
然后,从这里获取列:
columns = data.keys()
# ['column1', 'column3', 'column2']
现在,我们需要为列和值创建占位符:
placeholder_columns = ", ".join(data.keys())
# 'column1, column3, column2'
placeholder_values = ", ".join([":{0}".format(col) for col in columns])
# ':column1, :column3, :column2'
然后,我们创建 INSERT SQL 语句:
sql = "INSERT INTO table_name ({placeholder_columns}) VALUES ({placeholder_values})".format(
placeholder_columns=placeholder_columns,
placeholder_values=placeholder_values
)
# 'INSERT INTO table_name (column1, column3, column2) VALUES (:column1, :column3, :column2)'
现在,我们在 sql
中拥有的是带有命名参数的有效 SQL 语句。现在您可以使用数据执行此 SQL 查询:
cursor.execute(sql, data)
而且,由于 data
有键和值,它将使用查询中的命名占位符将值插入正确的列中。
查看 documentation 以了解如何使用命名参数。据我所知,您只需要担心插入值的清理。并且,有两种方法可以做到这一点 1) 使用问号样式,或 2) 命名参数样式。
(?, ?, ?) 语法仅适用于包含值的元组,恕我直言...这就是 sqlite3.OperationalError
的原因
我相信(!)您应该像这样构建它:
cursor.execute("INSERT INTO {tn} ({f1}, {f2}) VALUES (?, ?)".format(tn='testable', f1='foo', f1='bar'), ('test', 'test2',))
但是如果允许用户自己提供表名或字段名,这并不能解决注入问题。
我不知道有什么内置方法可以帮助解决这个问题。但是你可以使用这样的函数:
def clean(some_string):
return ''.join(char for char in some_string if char.isalnum())
清理用户给定的表名或字段名。这应该足够了,因为 table-/fieldnames 通常只包含字母数字字符。
如果
,也许检查一下可能更聪明
some_string == clean(some_string)
如果为 False,为了安全起见,放弃一个很好的例外。
在我与 sql 和 python 合作期间,我觉得您不需要让用户自己命名他的表和字段名。所以它 is/was 对我来说很少需要。
如果有人能详细说明并发表他的见解,我将不胜感激。
import sqlite3
conn = sqlite3.connect("db.sqlite")
cursor = conn.cursor()
## break your list into two, one for column and one for value
list = ['column1', 'column2', 'column3']
list2= ['value1', 'value2', 'value3']
cursor.execute("""insert into table_name("""+list[0]+""","""+list[1]+""","""+list[2]+""")
values ("""+list2[0]+""","""+list2[1]+""","""+list2[2]+""")""")
所以,这就是我最终实现的,我认为它非常 pythonic,但如果没有 Krysopath 的洞察力,我无法回答它:
columns = ['column1', 'column2', 'column3']
values = ['value1', 'value2', 'value3']
columns = ', '.join(columns)
insertString=("insert into table_name (%s) values (?,?,?,?)" %columns)
cursor.execute(insertString, values)
我是游标的新手,我正在尝试通过使用针对 sqlite3:[=12= 的清理方法构建动态 python sql 插入语句来练习]
import sqlite3
conn = sqlite3.connect("db.sqlite")
cursor = conn.cursor()
list = ['column1', 'column2', 'column3', 'value1', 'value2', 'value3']
cursor.execute("""insert into table_name (?,?,?)
values (?,?,?)""", list)
当我尝试使用它时,在值所在的行出现语法错误 "sqlite3.OperationalError: near "?""。尽管事实上当我对列进行硬编码(并从列表中删除列名)时,我没有问题。我可以用 %s 构建,但我知道首选经过消毒的方法。
如何干净地插入这些?还是我遗漏了一些明显的东西?
首先,我将从创建列和值的映射开始:
data = {'column1': 'value1', 'column2': 'value2', 'column3': 'value3'}
然后,从这里获取列:
columns = data.keys()
# ['column1', 'column3', 'column2']
现在,我们需要为列和值创建占位符:
placeholder_columns = ", ".join(data.keys())
# 'column1, column3, column2'
placeholder_values = ", ".join([":{0}".format(col) for col in columns])
# ':column1, :column3, :column2'
然后,我们创建 INSERT SQL 语句:
sql = "INSERT INTO table_name ({placeholder_columns}) VALUES ({placeholder_values})".format(
placeholder_columns=placeholder_columns,
placeholder_values=placeholder_values
)
# 'INSERT INTO table_name (column1, column3, column2) VALUES (:column1, :column3, :column2)'
现在,我们在 sql
中拥有的是带有命名参数的有效 SQL 语句。现在您可以使用数据执行此 SQL 查询:
cursor.execute(sql, data)
而且,由于 data
有键和值,它将使用查询中的命名占位符将值插入正确的列中。
查看 documentation 以了解如何使用命名参数。据我所知,您只需要担心插入值的清理。并且,有两种方法可以做到这一点 1) 使用问号样式,或 2) 命名参数样式。
(?, ?, ?) 语法仅适用于包含值的元组,恕我直言...这就是 sqlite3.OperationalError
的原因我相信(!)您应该像这样构建它:
cursor.execute("INSERT INTO {tn} ({f1}, {f2}) VALUES (?, ?)".format(tn='testable', f1='foo', f1='bar'), ('test', 'test2',))
但是如果允许用户自己提供表名或字段名,这并不能解决注入问题。
我不知道有什么内置方法可以帮助解决这个问题。但是你可以使用这样的函数:
def clean(some_string):
return ''.join(char for char in some_string if char.isalnum())
清理用户给定的表名或字段名。这应该足够了,因为 table-/fieldnames 通常只包含字母数字字符。
如果
,也许检查一下可能更聪明some_string == clean(some_string)
如果为 False,为了安全起见,放弃一个很好的例外。
在我与 sql 和 python 合作期间,我觉得您不需要让用户自己命名他的表和字段名。所以它 is/was 对我来说很少需要。
如果有人能详细说明并发表他的见解,我将不胜感激。
import sqlite3
conn = sqlite3.connect("db.sqlite")
cursor = conn.cursor()
## break your list into two, one for column and one for value
list = ['column1', 'column2', 'column3']
list2= ['value1', 'value2', 'value3']
cursor.execute("""insert into table_name("""+list[0]+""","""+list[1]+""","""+list[2]+""")
values ("""+list2[0]+""","""+list2[1]+""","""+list2[2]+""")""")
所以,这就是我最终实现的,我认为它非常 pythonic,但如果没有 Krysopath 的洞察力,我无法回答它:
columns = ['column1', 'column2', 'column3']
values = ['value1', 'value2', 'value3']
columns = ', '.join(columns)
insertString=("insert into table_name (%s) values (?,?,?,?)" %columns)
cursor.execute(insertString, values)