web-dev-qa-db-fra.com

Insérer Python Dictionnaire utilisant Psycopg2

Quelle est la meilleure façon d'insérer un dictionnaire python avec plusieurs clés dans une base de données Postgres sans avoir à énumérer toutes les clés?

J'aimerais faire quelque chose comme ...

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

cursor.execute('INSERT INTO song_table (song.keys()) VALUES (song)')
24
user3783608
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)))

Tirages:

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

Psycopg adapte un Tuple à un record et AsIs fait ce qui serait fait par la substitution de chaîne de Python.

25
Clodoaldo Neto

Vous pouvez également insérer plusieurs lignes à l'aide d'un dictionary. Si vous aviez ce qui suit:

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

Vous pouvez insérer les trois lignes dans le dictionnaire en utilisant:

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

Le cur.executemany l'instruction parcourra automatiquement le dictionnaire et exécutera la requête INSERT pour chaque ligne.

PS: Cet exemple est tiré de ici

17
vikas

Quelque chose dans ce sens devrait le faire:

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)

La partie clé est la chaîne générée de %s éléments, et en l'utilisant dans format, avec la liste transmise directement à l'appel execute, de sorte que psycopg2 puisse interpoler chaque élément dans le vals liste (empêchant ainsi possible injection SQL).

Une autre variante, en passant de dict à execute, serait d'utiliser ces lignes au lieu de vals, vals_str_list et vals_str d'en haut:

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)
11
khampson

Le nouveau module sql a été créé à cet effet et ajouté dans psycopg2 version 2.7. Selon la documentation:

Si vous devez générer dynamiquement une requête SQL (par exemple, choisir dynamiquement un nom de table), vous pouvez utiliser les fonctionnalités fournies par le module psycopg2.sql.

Deux exemples sont donnés dans la documentation: 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))

insérer dans la table ("foo", "bar", "baz") les valeurs (% 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))

insérer dans le tableau ("foo", "bar", "baz") les valeurs (% (foo) s,% (bar) s,% (baz) s)

Bien que la concaténation de chaînes produise le même résultat, elle ne devrait pas être utilisée à cette fin, selon la documentation de psycopg2:

Avertissement : jamais, jamais , [~ # ~] jamais [~ # ~] utilisez Python concaténation de chaînes (+) ou interpolation des paramètres de chaîne (%) pour passer des variables à une chaîne de requête SQL. Pas même sous la menace d'une arme.

4
Antoine Dusséaux