简体   繁体   English

如何将列名清晰地传递给游标Python / SQLite?

[英]How do you cleanly pass column names into cursor, Python/SQLite?

I'm new to cursors and I'm trying to practice by building a dynamic python sql insert statement using a sanitized method for sqlite3: 我是游戏的新手,我正在尝试通过使用sqlite3的清理方法构建动态python sql insert语句来练习:

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)

When I attempt to use this, I get a syntax error "sqlite3.OperationalError: near "?"" on the line with the values. 当我尝试使用它时,我得到一个语法错误“sqlite3.OperationalError:near”?“”在带有值的行上。 This is despite the fact that when I hard code the columns (and remove the column names from the list), I have no problem. 尽管事实上,当我对列进行硬编码(并从列表中删除列名)时,我没有问题。 I could construct with %s but I know that the sanitized method is preferred. 我可以使用%s构建但我知道已经过消毒的方法是首选。

How do I insert these cleanly? 如何干净地插入这些? Or am I missing something obvious? 还是我错过了一些明显的东西?

The (?, ?, ?) syntax works only for the tuple containing the values, imho... That would be the reason for sqlite3.OperationalError (?,?,?)语法仅适用于包含值的元组,imho ...这就是sqlite3.OperationalError的原因

I believe(!) that you are ought to build it similar to that: 我相信(!)你应该建立它类似于:

cursor.execute("INSERT INTO {tn} ({f1}, {f2}) VALUES (?, ?)".format(tn='testable', f1='foo', f1='bar'), ('test', 'test2',))

But this does not solve the injection problem, if the user is allowed to provide tablename or fieldnames himself, however. 但是,如果允许用户自己提供表名或字段名,这并不能解决注入问题。

I do not know any inbuilt method to help against that. 我不知道任何内置的方法来帮助解决这个问题。 But you could use a function like that: 但你可以使用这样的函数:

def clean(some_string):
    return ''.join(char for char in some_string if char.isalnum())

to sanitize the usergiven tablename or fieldnames. 清理usergiven tablename或fieldnames。 This should suffice, because table-/fieldnames usually consists only of alphanumeric chars. 这应该足够了,因为表/字段名通常只包含字母数字字符。

Perhaps it may be smart to check, if 如果,也许检查可能是明智的

some_string == clean(some_string)

And if False, drop a nice exception to be on the safe side. 如果为False,请放弃一个很好的例外以保证安全。

During my work with sql & python I felt, that you wont need to let the user name his tables and fieldnames himself, though. 在我使用sql和python的过程中,我觉得,你不需要让用户自己命名他的表和字段名称。 So it is/was rarely necessary for me. 所以这对我来说很少需要。

If anyone could elaborate some more and give his insights, I would greatly appreciate it. 如果有人能够详细说明并提出他的见解,我将非常感激。

First, I would start by creating a mapping of columns and values: 首先,我将首先创建列和值的映射:

data = {'column1': 'value1', 'column2': 'value2', 'column3': 'value3'}

And, then get the columns from here: 然后,从这里获取列:

columns = data.keys()  
# ['column1', 'column3', 'column2']

Now, we need to create placeholders for both columns and for values: 现在,我们需要为列和值创建占位符:

placeholder_columns = ", ".join(data.keys())
# 'column1, column3, column2'

placeholder_values = ", ".join([":{0}".format(col) for col in columns])
# ':column1, :column3, :column2'

Then, we create the INSERT SQL statement: 然后,我们创建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)'

Now, what we have in sql is a valid SQL statement with named parameters. 现在,我们在sql拥有的是一个带有命名参数的有效SQL语句。 Now you can execute this SQL query with the data: 现在,您可以使用以下数据执行此SQL查询:

cursor.execute(sql, data)

And, since data has keys and values, it will use the named placeholders in the query to insert the values in correct columns. 并且,由于data具有键和值,因此它将使用查询中的命名占位符将值插入正确的列中。

Have a look at the documentation to see how named parameters are used. 查看文档以了解如何使用命名参数。 From what I can see that you only need to worry about the sanitization for the values being inserted. 从我可以看到,您只需要担心插入值的清理。 And, there are two ways to do that 1) either using question mark style, or 2) named parameter style. 并且,有两种方法可以做到这一点1)使用问号样式,或2)命名参数样式。

So, here's what I ended up implementing, I thought it was pretty pythonic, but couldn't have answered it without Krysopath's insight: 所以,这就是我最终实现的内容,我认为它非常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)
    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]+""")""")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM