Python / postgres / psycopg2: obteniendo el ID de la fila recién insertada

99

Estoy usando Python y psycopg2 para interactuar con postgres.

Cuando inserto una fila ...

sql_string = "INSERT INTO hundred (name,name_slug,status) VALUES ("
sql_string += hundred_name + ", '" + hundred_slug + "', " + status + ");"
cursor.execute(sql_string)

... ¿cómo obtengo el ID de la fila que acabo de insertar? Molesto:

hundred = cursor.fetchall() 

devuelve un error, mientras usa RETURNING id:

sql_string = "INSERT INTO domes_hundred (name,name_slug,status) VALUES ("
sql_string += hundred_name + ", '" + hundred_slug + "', " + status + ") RETURNING id;"
hundred = cursor.execute(sql_string)

simplemente regresa None.

ACTUALIZACIÓN: También lo hace currval(aunque usar este comando directamente en postgres funciona):

sql_string = "SELECT currval(pg_get_serial_sequence('hundred', 'id'));"
hundred_id = cursor.execute(sql_string)

¿Alguien puede aconsejarme?

¡Gracias!

AP257
fuente

Respuestas:

206
cursor.execute("INSERT INTO .... RETURNING id")
id_of_new_row = cursor.fetchone()[0]

Y no cree cadenas SQL que contengan valores manualmente. Puede (¡y debe!) Pasar valores por separado, lo que hace innecesario escapar y la inyección de SQL imposible:

sql_string = "INSERT INTO domes_hundred (name,name_slug,status) VALUES (%s,%s,%s) RETURNING id;"
cursor.execute(sql_string, (hundred_name, hundred_slug, status))
hundred = cursor.fetchone()[0]

Consulte los documentos de psycopg para obtener más detalles: http://initd.org/psycopg/docs/usage.html#passing-parameters-to-sql-queries

ThiefMaster
fuente
12
Solo para aclarar, la idde RETURNING iddebe ser el nombre del campo del campo de número de serie / primaria.
joshden
9
cursor fetchone me da "no hay resultados para buscar".
Leonid
@Leonid, ¿te diste cuenta de esto?
Alison S
4
@AlisonS @Leonid Tuve el mismo error, pero agregarlo RETURNING idal final de la INSERTconsulta lo solucionó.
Banjer
Tal vez solo una pequeña nota, pero un punto importante para mencionar para todos: asegúrese de que solo está usando el cursor .execute () y no un cursor .mogrify () antes del comando execute () , de lo contrario (como en mi caso) cursor.fetchone () no tendrá ningún resultado! Al usar solo el cursor .execute () sin "nada" antes de ese comando, recibirá una identificación.
TheHeroOfTime
14

Terminé aquí porque tuve un problema similar, pero estamos usando Postgres-XC, que aún no admite la cláusula RETURNING ID. En ese caso, puede utilizar:

cursor.execute ('INSERT INTO ........')
cursor.execute ('SELECCIONAR LASTVAL ()')
lastid = cursor.fetchone () ['lastval']

¡Por si acaso le fuera útil a alguien!

Jamie Brown
fuente
4
Solo recuerde: hacerlo en dos declaraciones como esa corre un riesgo (muy pequeño) de condiciones de carrera, si algo inserta una fila en la base de datos directamente después de usted, pero antes de que su comando lastval () devuelva el valor actual de la secuencia.
Dave Thomas