Configure SQLAlchemy para que use la SERIE PostgreSQL para la generación de identidad

Fondo:

La aplicación que estoy desarrollando actualmente está en transición de SQLite3 a PostgreSQL. Todos los datos se han migrado correctamente, usando el .dump de la base de datos actual, cambiando todas las tablas del tipo

 CREATE TABLE foo ( id INTEGER NOT NULL, bar INTEGER, ... PRIMARY KEY (id), FOREIGN KEY(bar) REFERENCES foobar (id), ... ); 

a

 CREATE TABLE foo ( id SERIAL NOT NULL, bar INTEGER, ... PRIMARY KEY (id), FOREIGN KEY(bar) REFERENCES foobar (id) DEFERRABLE, ... ); 

y SET CONSTRAINTS ALL DEFERRED; .

Desde que uso SQLAlchemy, esperaba que las cosas funcionaran bien a partir de ese momento, después de cambiar el engine , por supuesto. Pero el problema parece ser el autoincremento de la clave primaria a un valor único en INSERT .

La tabla, digamos foo , actualmente tengo problemas con más de 7500 filas, pero el current value la secuencia foo_id_seq se establece en 5 (porque he intentado las inserciones cinco veces y todas han fallado).

Pregunta:

Así que ahora mi pregunta es que sin proporcionar explícitamente el id , en la statement INSERT , ¿cómo puedo hacer que Postgres asigne automáticamente un valor único al campo id si foo ? O más específicamente, ¿la secuencia devuelve un valor único para ella?

Azúcar:

Consigue todo eso a través de la interfaz SQLAlchemy.

Detalles del entorno:

  • Python 2.6
  • SQLAlchemy 8.2
  • PostgreSQL 9.2
  • psycopg2 – 2.5.1 (dt dec pq3 ext)

PD: Si alguien encuentra un título más apropiado para esta pregunta, edítelo.

Su PRIMARY KEY debe definirse para utilizar una SEQUENCE como DEFAULT , ya sea a través del pseudo tipo SERIAL :

 CREATE TABLE blah ( id serial primary key, ... ); 

o una SEQUENCE explícita:

 CREATE SEQUENCE blah_id_seq; CREATE TABLE blah ( id integer primary key default nextval('blah_id_seq'), ... ); ALTER SEQUENCE blah_id_seq OWNED BY blah.id; 

Esto se discute en la documentación de SQLAlchemy .

Puedes agregar esto a una tabla existente:

 CREATE SEQUENCE blah_id_seq OWNED BY blah.id; ALTER TABLE blah ALTER COLUMN id SET DEFAULT nextval('blah_id_seq'); 

Si prefiere restaurar un volcado, agregue secuencias manualmente.

Si hay datos existentes que ha cargado directamente en las tablas con COPY o similar, debe establecer el punto de inicio de la secuencia:

 SELECT setval('blah_id_seq', max(id)+1) FROM blah; 

Yo diría que es probable que el problema tenga que ver con su desarrollo en SQLite, luego hacer un volcado y restaurar ese volcado en PostgreSQL. SQLAlchemy espera crear el esquema por sí mismo con los valores predeterminados y las secuencias apropiadas.

Lo que te recomiendo que hagas es que SQLAlchemy cree una base de datos nueva y vacía. Voltee los datos para cada tabla desde la base de datos SQLite a CSV, luego COPY esos datos en las tablas PostgreSQL. Finalmente, actualice las secuencias con setval para que generen los valores apropiados.

De una forma u otra, deberá asegurarse de que se crean las secuencias apropiadas. Puede hacerlo mediante los tipos de pseudo-columna SERIAL , o mediante la creación de SEQUENCE manual y la configuración DEFAULT , pero debe hacerlo. De lo contrario, no hay manera de asignar un ID generado a la tabla de una manera eficiente y segura para la concurrencia.

Utilizar

 alter sequence foo_id_seq restart with 7600 

debería darle 7601 la próxima vez que llame a la secuencia.

http://www.postgresql.org/docs/current/static/sql-altersequence.html

Y luego los valores posteriores. Solo asegúrese de reiniciarlo con un valor> la última ID.