2009-08-22 7 views
64

voglio fare qualcosa di simile:sqlalchemy flush() e ottieni l'id inserito?

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() 

Ma f.id vale None quando ho provato. Come posso farlo funzionare?

-Dan

+2

È possibile inizializzare il motore SA con 'echo = True' e vedere quale SQL viene eseguito in tempo di svuotamento? Quello che descrivi * dovrebbe * funzionare e darti l'id, ma potrebbe esserci qualche altro problema che si traduce in f.id in Nessuno. –

risposta

37

Il codice di esempio avrebbe dovuto funzionare così com'è. Sqlalchemy dovrebbe fornire un valore per f.id, supponendo che sia una colonna di chiave primaria autogenerante. gli attributi della chiave primaria vengono popolati immediatamente all'interno del processo flush() man mano che vengono generati e non deve essere richiesta alcuna chiamata a commit(). Quindi la risposta qui sta nei dettagli della tua mappatura, se ci sono stranezze del backend in uso (come, SQLite non genera valori interi per una chiave primaria composita) e/o cosa dice l'SQL emesso quando tu attiva l'eco.

+0

Sei corretto, un rapido controllo nella shell mostra che popola il campo chiave primaria con un valore. Dovrò indagare sul motivo per cui non ha funzionato nella pratica. – Eloff

+2

"il tuo codice di esempio dovrebbe fornire un valore" sembra che tu stia dicendo "dovresti aver dato un valore per id in primo luogo", piuttosto che "quel codice che avresti dovuto funzionare così com'è". Mi è diventato chiaro che intendevi il secondo piuttosto che il primo solo dopo la terza lettura. Potresti chiarire? – stochastic

-7

Si dovrebbe provare a utilizzare session.save_or_update(f) invece di session.add(f).

+1

'save_or_update' è stato deprecato da 0,5 circa. 'session.add()' dovrebbe farlo. –

93

Ho appena incontrato lo stesso problema, e dopo i test ho riscontrato che nessuna di queste risposte è sufficiente.

Attualmente, o come di SQLAlchemy .6+, c'è una soluzione molto semplice (non so se questo esiste nella versione precedente, anche se immagino che fa):

session.refresh()

Quindi, il codice sarebbe simile a questa:

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. 

Ecco come farlo.

+6

Questo si sta avvicinando a una risposta che potrebbe funzionare per me, ma ricevo il seguente errore: InvalidRequestError: Impossibile aggiornare l'istanza '<....>'. Appare dopo il flush che l'istanza semplicemente non esiste più.Apprezzo qualsiasi intuizione. – PlaidFan

+1

Mi hai appena salvato il culo. Non penso che userò mai più l'ORM proveniente da Django. Il comando flush() NON funziona come IMHO documentato. Aggiornamento –

+1

, ho dovuto usare '' 'sessionmaker (autoflush = True)' '', che combo w/refresh() mi ha fornito l'ID riga. #grrr –

4

a differenza della risposta fornita da dpb, non è necessario un aggiornamento. una volta scaricata, è possibile accedere al campo id, sqlalchemy aggiorna automaticamente l'id che viene generato automaticamente nel backend

Ho riscontrato questo problema e ho capito il motivo esatto dopo alcune indagini, il mio modello è stato creato con id come intero campo e nella mia forma l'id era rappresentata con hiddenfield (dato che non volevo mostrare l'id nella mia forma). Il campo nascosto viene rappresentato per default come un testo. una volta modificato il modulo in integerfield con widget = hiddenInput(), il problema è stato risolto.

+1

Come detto solo refresh() ha funzionato per me. Nel fare una migrazione dei dati avevo bisogno dell'ID di riga in un ciclo per popolare un FK. Ho provato ogni combinazione di commit, flush, session hacking e refresh() era l'unica cosa che funzionava. I miei dati sono super puliti e sto solo trovando che SQLA non è poi così buono (avendo una notevole exp in almeno 5 major ORMS). È sufficiente eseguire il wrapping in 5+ ore cercando di ottenere l'id riga per un add() -> commit()/flush(). –

1

Una volta ho avuto un problema con l'assegnazione di 0 all'ID prima di chiamare il metodo session.add. L'ID è stato assegnato correttamente dal database ma l'ID corretto non è stato recuperato dalla sessione dopo session.flush().