【问题标题】:Python Sqlite3 - Using f strings for update database functionPython Sqlite3 - 使用 f 字符串更新数据库函数
【发布时间】:2018-12-21 02:47:43
【问题描述】:

我有自己的个人数据库,我是为了好玩而创建的(所以我不关心 sql 注入作为我自己创建的私有数据库),并且我正在尝试更改我创建的使用字符串格式 (.format()) 和占位符(?、%s 等)并改用 f 字符串。我遇到了一个问题,在我将 sqlite3 查询更改为 f 字符串后,我的一个将指定列更新为指定行的函数将无法运行。

这是我当前使用 f 个字符串的函数:

import sqlite3
from tabulate import tabulate
conn = sqlite3.connect("Table.db")
c = conn.cursor()

def updatedb(Column, Info, IdNum):  
    with conn:
        data = c.execute(f"UPDATE Table_name SET {Column} = {Info} WHERE IdNum={IdNum}")
        c.execute(f"SELECT * FROM Table_name WHERE IdNum = {IdNum}")
    print(tabulate(data, headers="keys", tablefmt="grid", stralign='center', numalign='center'))

该函数通过使用您想要在该列中的新信息更新指定行的指定列来更新表。例如,在 3 x 3 表中,如果该列是年龄或其他内容,我可以使用该函数将第 1 行第 2 列更新为 18,而不是第 1 行第 2 列。之后的 select 查询只是选择已更新的特定行,之后的 print 语句使用 tabulate 包打印出整齐有序的表格。

每当我尝试使用此功能时遇到的错误是:

sqlite3.OperationalError: no such column: Info

无论我在函数中为 Info 变量输入什么,错误都会变成什么,但我不知道如何解决这个问题。

这是我在尝试更改为 f 字符串之前的更新语句,对我来说效果很好:

data = c.execute("UPDATE Table_name SET {} = ? WHERE IdNum=?".format(Column), (Info, IdNum))

将上述查询更改为 f 字符串似乎没有那么大的变化,但它不起作用,因此我们将不胜感激。

【问题讨论】:

  • 当然变化很大。你搞乱了参数化。你目前的做法没有问题,不要摆脱?

标签: python python-3.x sqlite f-string


【解决方案1】:

这里的问题是理解参数化 - 它仅适用于参数,不适用于列名和其他内容。

在这个例子中:

 query = 'SELECT * FROM foo WHERE bar = ? AND baz = ?'
 params = (a, b)
 cursor.execute(query, params)

请注意,查询和数据分别分别传递给.execute - 进行插值是数据库的工作 - 让您摆脱引用地狱,并通过禁用任何一种sql注入。它还可以更好地执行 - 它允许数据库缓存已编译的查询并在您更改参数时使用它。

现在这只适用于数据。如果你想在变量中包含实际的列名,你必须自己在查询中插入它:

 col1 = 'bar'
 col2 = 'baz'
 query = f'SELECT * FROM foo WHERE {col1} = ? AND {col2} = ?'
 cursor.execute(query, params)

【讨论】:

    【解决方案2】:

    参数化和字符串替换是两个截然不同的东西。

    在最基本的层面上,您的问题是字符串替换正在生成以下形式的命令:

     . . . SET some_column = some_info . . .
    

    SQL 需要的地方

     . . . SET some_column = 'some_info' . . .
    

    (即字符串值的引号)。 SQLite 将不带引号的字符串解释为由列名组成的表达式。

    您可能认为,您无法通过简单地将单引号添加到格式字符串中来解决此问题。如果替换值本身包含单引号会发生什么?这种方式既存在字符串转义的疯狂,也存在 SQL 注入的危险。

    相反,只需使用参数化。

    但是,请注意,您不能参数化列名 ({Column}),您必须为此使用字符串替换,同时注意不要发生注入。

    【讨论】:

      【解决方案3】:

      要改进上面关于f-strings 使用的nosklo 的答案,您只需在变量周围使用转义引号,以便将它们作为字符串发送到SQLite:

      import sqlite3
      
      conn = sqlite3.connect("somedatabase.db")
      c = conn.cursor()
      
      def updatedb(colname, colvalue, rowid):
          with conn:
              c.execute(f"UPDATE tablename SET \"{colname}\" = \"{colvalue}\" WHERE rowidentifier = \"{rowid}\"")
      

      注意

      出于安全原因,请勿在依赖外部用户输入的数据库中使用字符串插值。但是,如果你清理输入字符串,我想你可以让它工作。

      【讨论】:

        【解决方案4】:

        我正在使用 mysql.connector

        query = "INSERT INTO PICS (name,image) VALUES (%s,%s)"
        param = (fname, DATA)
        cursor.execute(query, param)
        print("DONEEEEEE" * 100)
        conn.commit()
        cursor.close()
        conn.close()
        

        这是最新版本的'8.0.27' 2021年

        这对我有用!!!!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-02-21
          • 2020-04-30
          • 2020-09-14
          • 1970-01-01
          • 1970-01-01
          • 2021-04-14
          • 1970-01-01
          相关资源
          最近更新 更多