简体   繁体   中英

How can I (safely) convert a dictionary into an UPDATE statement for sqlite in Python?

Say for example, I have a table of students, and I have a Python dictionary

mydict = {"fname" : "samwise", "lname" : "gamgee", "age" : 13}

How can I safely generate a Python function that can UPDATE this into my student table? (In my use-case I can safely assume that the student already exists in the table, AND I KNOW the id already)

I have created a function that achieves this functionality, but I can't help but think it's a bit crude, and perhaps open to SQL injection attacks

def sqlite_update(conn, table, data, pkeyname, pkeyval):
    set_lines = ""
    for k,v in data.items():
        set_lines += "{} = '{}', ".format(k,v)

    set_lines = set_lines[:-2] #remove space and comma from last item

    sql = "UPDATE {0} SET {1} WHERE {2} = '{3}'"
    statement = sql.format(table, set_lines, pkeyname, pkeyval)

    conn.execute(statement)
    conn.commit()

And to update I just call

sqlite_update(conn, "student", mydict, "id", 1)

As I assume you are using sqlalchemy . In this case, you can use sqlalchemy.sql.text function which escapes strings if required.

You can try to adjust your function as below.

from sqlalchemy.sql import text

def sqlite_update(conn, table, data, pkeyname, pkeyval):
    set_lines = ",".join([f"{k}=:{k}" for k in data.keys()])
    statement = text(f"UPDATE {table} SET {set_lines} WHERE {pkeyname} = :pkeyval")

    args = dict(data)
    args["pkeyval"] = pkeyval
    conn.execute(statement, args)
    conn.commit()

For more details, refer to sqlalchemy official documentation on text function.

EDIT

As for sqlite3 connection you can do basically the same thing as above, with slight changes.

def sqlite_update(conn, table, data, pkeyname, pkeyval):
    set_lines = ",".join([f"{k}=:{k}" for k in data.keys()])
    statement = f"UPDATE {table} SET {set_lines} WHERE {pkeyname} = :pkeyval"

    args = dict(data)
    args["pkeyval"] = pkeyval
    conn.execute(statement, args)
    conn.commit()

Refer to sqlite3 execute

This is indeed widely opened to SQL injection, because you build the query as a string including its values , instead of using a parameterized query.

Building a parameterized query with Python is easy:

def sqlite_update(conn, table, data, pkeyname, pkeyval):
    query = f"UPDATE {table} SET " + ', '.join(
        "{}=?".format(k) for k in data.keys()) + f" WHERE {pkeyname}=?"
    # uncomment next line for debugging
    # print(query, list(data.values()) + [pkeyval])
    conn.execute(query, list(data.values()) + [pkeyval])

With your example, the query displayed by the debug print line is:

UPDATE student SET fname=?, lname=?, age=? WHERE id=?

with the following values list: ['samwise', 'gamgee', 13, 1]

But beware, to be fully protected from SQL injection, you should sanitize the table and field names to ensure they contain no dangerous characters like ;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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