2009-08-22 22 views
64

quiero hacer algo como esto:sqlalchemy flush() y obtener la identificación insertada?

f = Foo(bar='x') 
session.add(f) 
session.flush() 

# do additional queries using f.id before commit() 
print f.id # should be not None 

session.commit() 

Pero es f.id Ninguno cuando lo intento. ¿Cómo puedo hacer que esto funcione?

-Dan

+2

¿Se puede inicializar el motor de SA con 'echo = True', y ver qué SQL se ejecuta en tiempo de descarga? Lo que usted describe * debería * funcionar y darle la identificación, pero puede haber algún otro problema que resulte en que fida sea Ninguno. –

Respuesta

37

Su código de muestra debería haber funcionado como está. Sqlalchemy debería proporcionar un valor para f.id, suponiendo que es una columna de clave principal autogenerativa. Los atributos de clave primaria se rellenan inmediatamente dentro del proceso flush() a medida que se generan y no es necesario llamar a commit(). Así que la respuesta aquí radica en los detalles de su mapeo, si hay alguna peculiaridad extraña del backend en uso (como, por ejemplo, SQLite no genera valores enteros para una clave primaria compuesta) y/o lo que dice el SQL emitido cuando usted enciende el eco

+0

Está en lo correcto, una comprobación rápida en el shell muestra que rellena el campo de clave principal con un valor. Tendré que investigar por qué no estaba funcionando en la práctica. – Eloff

+2

"su código de ejemplo debería proporcionar un valor" suena como si estuviese diciendo "debería haber dado un valor para la identificación en primer lugar", en lugar de "ese código debería haber funcionado como es". Me quedó claro que te referías a lo último en lugar de lo primero solo después de la tercera lectura. ¿Podrías aclarar? – stochastic

-7

debería intentar usar session.save_or_update(f) en lugar de session.add(f).

+1

'save_or_update' ha quedado en desuso desde 0.5 o menos. 'session.add()' debería hacerlo. –

93

Acabo de encontrar el mismo problema, y ​​después de las pruebas he encontrado que NINGUNA de estas respuestas es suficiente.

En la actualidad, o como de sqlalchemy .6+, hay una solución muy simple (no sé si esto existe en la versión anterior, aunque me imagino que lo hace):

session.refresh()

Por lo tanto, el código sería algo como esto:

f = Foo(bar=x) 
session.add(f) 
session.flush() 
# At this point, the object f has been pushed to the DB, 
# and has been automatically assigned a unique primary key id 

f.id 
# is None 

session.refresh(f) 
# refresh updates given object in the session with its state in the DB 
# (and can also only refresh certain attributes - search for documentation) 

f.id 
# is the automatically assigned primary key ID given in the database. 

Eso es cómo hacerlo.

+6

Esto se está acercando a una respuesta que podría funcionar para mí pero recibo el siguiente error: InvalidRequestError: No se pudo actualizar la instancia '<....>'. Después de la descarga, parece que la instancia simplemente ya no existe.Apreciar cualquier idea. – PlaidFan

+1

Acabas de salvarme el culo. No creo que vuelva a utilizar el ORM de Django. El comando flush() NO funciona como documentado en mi humilde opinión. –

+1

Actualización, tuve que usar '' 'sessionmaker (autoflush = True)' '', ese combo w/refresh() me proporcionó el ID de fila. #grrr –

4

a diferencia de la respuesta dada por dpb, no es necesario actualizar. una vez que descarga, puede acceder al campo id, sqlalchemy actualiza automáticamente el id que se genera automáticamente en el servidor

Encontré este problema y calculé el motivo exacto después de una investigación, mi modelo se creó con id como integerfield y en mi forma, la identificación estaba representada con hiddenfield (ya que no quería mostrar la identificación en mi formulario). El campo oculto está representado por defecto como un texto. una vez que cambié el formulario a integerfield con widget = hiddenInput()) el problema fue resuelto.

+1

Como dije, solo refresh() funcionó para mí. Al hacer una migración de datos, necesitaba el ID de fila en un bucle para llenar un FK. Probé cada combinación de commit, flush, session hacking y refresh(), fue lo único que funcionó. Mis datos están muy limpios y solo estoy descubriendo que SQLA no es realmente tan bueno (teniendo una experiencia considerable en al menos 5 ORMS principales). Solo terminando en más de 5 horas tratando de obtener la identificación de la fila para un add() -> commit()/flush(). –

1

Una vez tuve un problema con haber asignado 0 a la identificación antes de llamar al método session.add. La base de datos asignó correctamente la identificación, pero la identificación correcta no se recuperó de la sesión después de session.flush().

Cuestiones relacionadas