使用Psycopg2插入Python字典

eni9jsuy  于 2023-04-19  发布在  Python
关注(0)|答案(8)|浏览(194)

什么是最好的方法来插入一个Python字典与许多键到Postgres数据库,而不必枚举所有键?
我想做一些...

song = dict()
song['title'] = 'song 1'
song['artist'] = 'artist 1'
...

cursor.execute('INSERT INTO song_table (song.keys()) VALUES (song)')
ruarlubt

ruarlubt1#

from psycopg2.extensions import AsIs

song = {
    'title': 'song 1',
    'artist': 'artist 1'
}

columns = song.keys()
values = [song[column] for column in columns]

insert_statement = 'insert into song_table (%s) values %s'

    # cursor.execute(insert_statement, (AsIs(','.join(columns)), tuple(values)))
print cursor.mogrify(insert_statement, (AsIs(','.join(columns)), tuple(values)))

图纸:

insert into song_table (artist,title) values ('artist 1', 'song 1')

Psycopg将tuple适配为record,而AsIs则执行Python的字符串替换操作。

tzxcd3kk

tzxcd3kk2#

您也可以使用dictionary插入多行。如果您有以下内容:

namedict = ({"first_name":"Joshua", "last_name":"Drake"},
            {"first_name":"Steven", "last_name":"Foo"},
            {"first_name":"David", "last_name":"Bar"})

您可以使用以下命令在字典中插入所有三行:

cur = conn.cursor()
cur.executemany("""INSERT INTO bar(first_name,last_name) VALUES (%(first_name)s, %(last_name)s)""", namedict)

cur.executemany语句将自动遍历字典并对每一行执行INSERT查询。
PS:这个例子取自here

nszi6y05

nszi6y053#

沿着以下思路应该可以做到这一点:

song = dict()
song['title'] = 'song 1'
song['artist'] = 'artist 1'

cols=song.keys();

vals = [song[x] for x in cols]
vals_str_list = ["%s"] * len(vals)
vals_str = ", ".join(vals_str_list)

cursor.execute("INSERT INTO song_table ({cols}) VALUES ({vals_str})".format(
               cols = cols, vals_str = vals_str), vals)

关键部分是生成的%s元素字符串,并在format中使用该字符串,将列表直接传递给execute调用,以便 psycopg2 可以插入vals列表中的每个项目(从而防止可能的 *SQL注入 *)。
另一个变体,将dict传递到execute,将使用这些行而不是上面的valsvals_str_listvals_str

vals_str2 = ", ".join(["%({0})s".format(x) for x in cols])

cursor.execute("INSERT INTO song_table ({cols}) VALUES ({vals_str})".format(
               cols = cols, vals_str = vals_str2), song)
xu3bshqb

xu3bshqb4#

新的sql模块是为此目的创建的,并添加到psycopg2版本2.7中。根据文档:
如果需要动态生成SQL查询(例如,动态选择表名),可以使用psycopg2.sql模块提供的工具。
文档中给出了两个示例:http://initd.org/psycopg/docs/sql.html

names = ['foo', 'bar', 'baz']

q1 = sql.SQL("insert into table ({}) values ({})").format(
    sql.SQL(', ').join(map(sql.Identifier, names)),
    sql.SQL(', ').join(sql.Placeholder() * len(names)))
print(q1.as_string(conn))

插入到表(“foo”,“bar”,“baz”)值(%s,%s,%s)

q2 = sql.SQL("insert into table ({}) values ({})").format(
    sql.SQL(', ').join(map(sql.Identifier, names)),
    sql.SQL(', ').join(map(sql.Placeholder, names)))
print(q2.as_string(conn))

插入表(“foo”,“bar”,“baz”)值(%(foo)s,%(bar)s,%(baz)s)
虽然字符串连接会产生相同的结果,但根据psycopg2文档,它不应用于此目的:

警告:永远不要,永远不要永远不要使用Python字符串连接(+)或字符串参数插值(%)将变量传递给SQL查询字符串。即使在枪口下也不行。

kqqjbcuj

kqqjbcuj5#

另一种从字典**查询mySQL或pgSQL的方法是使用构造%(dic_key)s,它将被字典中与dic_key对应的值替换,如{'dic_key': 'dic value'}工作完美,并防止sqlInjection测试:Python 2.7如下:

# in_dict = {u'report_range': None, u'report_description': None, 'user_id': 6, u'rtype': None, u'datapool_id': 1, u'report_name': u'test suka 1', u'category_id': 3, u'report_id': None}

cursor.execute('INSERT INTO report_template (report_id, report_name, report_description, report_range, datapool_id, category_id, rtype, user_id) VALUES ' \
                                                                 '(DEFAULT, %(report_name)s, %(report_description)s, %(report_range)s, %(datapool_id)s, %(category_id)s, %(rtype)s, %(user_id)s) ' \
                                                                 'RETURNING "report_id";', in_dict)

输出:INSERT INTO report_template (report_id, report_name, report_description, report_range, datapool_id, category_id, rtype, user_id) VALUES (DEFAULT, E'test suka 1', NULL, NULL, 1, 3, NULL, 6) RETURNING "report_id";

p8ekf7hl

p8ekf7hl6#

使用execute_valueshttps://www.psycopg.org/docs/extras.html更快,并且有一个fetch参数来返回一些东西。接下来有一些代码可能会有所帮助。columns是一个字符串,如col_name1, col_name2模板是允许匹配的字符串,如%(col_name1)s, %(col_name2)

def insert(cur: RealDictCursor,
        table_name: str,
        values: list[dict],
        returning: str = ''
        ):
    if not values:
        return []

    query = f"""SELECT
                    column_name AS c
                FROM
                    information_schema.columns
                WHERE
                    table_name = '{table_name}'
                AND column_default IS NULL;"""
    cur.execute(query)
    columns_names = cur.fetchall()

    fetch = False
    if returning:
        returning = f'RETURNING {returning}'
        fetch = True

    columns = ''
    template = ''
    for col in columns_names:
        col_name = col['c']
        for val in values:
            if col_name in val:
                continue
            val[col_name] = None

        columns += f'{col_name}, '
        template += f'%({col_name})s, '
    else:
        columns = columns[:-2]
        template = template[:-2]

    query = f"""INSERT INTO {table_name} 
                    ({columns})
                    VALUES %s {returning}"""
    return execute_values(cur, query, values,
                        template=f'({template})', fetch=fetch)
ippsafx7

ippsafx77#

Clodaldos的答案在python3的“ordered dict”promise中变得更简单:

from psycopg2.extensions import AsIs

song = dict(title='song 1', artist='artist 1')

insert_statement = 'insert into song_table (%s) values %s'
cursor.execute(insert_statement, (AsIs(','.join(song.keys())), tuple(song.values())))
nvbavucw

nvbavucw8#

Python有一些内置的特性,比如joinlist,可以用来生成查询。另外,Python字典提供了keys()values(),可以分别用来提取列名和列值。我就是用这个方法,应该可以用。

song = dict()
song['title'] = 'song 1'
song['artist'] = 'artist 1'

query = '''insert into song_table (''' +','.join(list(song.keys()))+''') values '''+ str(tuple(song.values()))
cursor.execute(query)

相关问题