Подтвердить что ты не робот

Вставить словарь Python с помощью Psycopg2

Каков наилучший способ вставить словарь python со многими ключами в базу данных Postgres без необходимости перечислять все ключи?

Я хотел бы сделать что-то вроде...

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

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

Ответ 1

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.

Ответ 2

Вы также можете вставить несколько строк с помощью 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: Этот пример взят из здесь

Ответ 3

Что-то вроде этого должно сделать это:

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 Injection).

Другой вариант, передавая dict для execute, будет использовать эти строки вместо vals, vals_str_list и vals_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)

Ответ 4

Новый модуль 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. Даже под прицелом.

Ответ 5

другой подход для запроса к 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";