mogrify и возвращение с psycopg2

Я пытаюсь автоматически генерировать запросы. Я думал об использовании executemany, но мне нужно использовать оператор возврата, поэтому я сделал:

def format_bind(cols, rows):
    return '(' + '), ('.join([', '.join(['%s'] * cols)] * rows) + ')'        

def insert_many(table, values, id_column):
                if not values:
                    return []

                keys = values[0].keys()
                conn = psycopg2.connect("dbname='db' user='postgres' host='localhost' password='postgres'")
            cursor = conn.cursor()
            query = cursor.mogrify("INSERT INTO {} ({}) VALUES {} RETURNING {}".format(table,
                                                                                         ', '.join(keys),
                                                                                         format_bind(len(keys), len(values)),
                                                                                         id_column),
                                   [tuple(v.values()) for v in values])
            cursor.execute(query)
            return [t[0] for t in (cursor.fetchall())]

Проблема в том, что когда я запускаю его, я получаю: error list index out of range Может ли кто-нибудь помочь мне исправить это?


person Sam    schedule 28.12.2015    source источник


Ответы (1)


Проблема заключалась в том, что я думал, что должен поставить интерполяцию строкового параметра для каждого вставляемого значения. Я объясню это:

Допустим, у меня есть список с двумя словарями (длиной три) с данными для вставки:

lst = [{'a': 21, 'b': 9, 'c': 33}, {'a': 76, 'b': 84, 'c': 46}]

Чтобы вставить эти значения, я сделал что-то похожее на:

query = curs.mogrify("INSERT INTO {} ({}) VALUES {} RETURNING {}".format(
                        table,
                        ', '.join(lst[0].keys()),
                        ', '.join(['%s'] * len(lst[0].values())),
                        'id'
                    ), [tuple(v.values()) for v in lst])

добавление всего трех '%s' (по одному для каждого элемента в одном словаре в lst). Результатом этого является сообщение об исключении error list index out of range, и это происходит потому, что curs.mogrify() ожидает только один '%s' для каждого словаря в lst, поэтому в этом случае требуется только два '%s' вместо трех .

Следовательно, правильная форма для вставки данных из lst:

query = curs.mogrify("INSERT INTO {} ({}) VALUES {} RETURNING {}".format(
                            table,
                            ', '.join(lst[0].keys()),
                            ', '.join(['%s'] * len(lst)),
                            'id'
                        ), [tuple(v.values()) for v in lst])

Замена len(lst[0].values()) на len(lst).

Вот как я решил свою проблему (я не понял этого, потому что я не прочитал код примера должным образом). Надеюсь, это поможет.

Сэм

person Sam    schedule 30.05.2017
comment
э, просто чтобы добавить то, что я тоже упустил - %s, следующие за VALUES, не заключены в круглые скобки при использовании mogrify - person AiRiFiEd; 16.03.2021