web-dev-qa-db-fra.com

sqlalchemy flush () et obtenir l'identifiant inséré?

Je veux faire quelque chose comme ça:

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

Mais f.id est None lorsque je l'essaye. Comment puis-je faire en sorte que cela fonctionne?

97
Eloff

Votre exemple de code aurait dû fonctionner tel quel. SQLAlchemy doit fournir une valeur pour f.id, En supposant qu'il s'agit d'une colonne de clé primaire à génération automatique. Les attributs de clé primaire sont remplis immédiatement dans le processus flush() lorsqu'ils sont générés, et aucun appel à commit() ne doit être requis. La réponse réside donc dans un ou plusieurs des éléments suivants:

  1. Les détails de votre cartographie
  2. S'il y a des bizarreries étranges du backend en cours d'utilisation (comme, SQLite ne génère pas de valeurs entières pour une clé primaire composite)
  3. Ce que dit le SQL émis lorsque vous activez l'écho
54
zzzeek

Je viens de rencontrer le même problème, et après avoir testé, j'ai constaté que AUCUNE de ces réponses n'est suffisante.

Actuellement, ou à partir de sqlalchemy .6+, il existe une solution très simple (je ne sais pas si cela existe dans la version précédente, bien que j'imagine que oui):

session.refresh ()

Donc, votre code ressemblerait à ceci:

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.

Voilà comment procéder.

113
dpb

Merci pour tout le monde. J'ai résolu mon problème en modifiant le mappage de colonne. Pour moi, autoincrement=True est requis.

Origine:

id = Column('ID', Integer, primary_key=True, nullable=False)

après modification:

id = Column('ID', Integer, primary_key=True, autoincrement=True, nullable=True)

puis

session.flush()  
print(f.id)

est ok!

11
poloxue

contrairement à la réponse donnée par dpb, un rafraîchissement n'est pas nécessaire. une fois que vous rincez, vous pouvez accéder au champ id, sqlalchemy actualise automatiquement l'id qui est généré automatiquement au niveau du backend

J'ai rencontré ce problème et compris la raison exacte après une enquête, mon modèle a été créé avec id comme champ entier et sous ma forme, l'ID était représenté avec hiddenfield (car je ne voulais pas afficher l'id dans mon formulaire). Le champ masqué est représenté par défaut sous forme de texte. une fois que j'ai changé le formulaire en champ entier avec widget = hiddenInput ()), le problème a été résolu.

6
Ryan

Une fois, j'ai eu un problème avec l'attribution de 0 À id avant d'appeler la méthode session.add. L'ID a été correctement attribué par la base de données mais l'ID correct n'a pas été récupéré de la session après session.flush().

1
babky