sqlalchemy flush()と挿入されたIDを取得しますか?


114

私はこのようなことをしたいです:

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

しかし、f.idであるNone、私はそれをしようとします。これを機能させるにはどうすればよいですか?


2
SAエンジンをecho=Trueで初期化して、フラッシュ時に実行されるSQLを確認できますか?あなたが説明したこと機能し、あなたにidを与えるはずですが、f.idがNoneになる他の問題があるかもしれません。
Pavel Repin

回答:


63

サンプルコードはそのままで機能するはずです。SQLAlchemyはf.id、自動生成の主キー列を想定して、の値を提供する必要があります。主キー属性は、生成されるとすぐにflush()プロセス内に入力され、への呼び出しはcommit()必要ありません。したがって、ここでの答えは次の1つ以上にあります。

  1. マッピングの詳細
  2. 使用中のバックエンドの奇妙な癖がある場合(SQLiteが複合主キーの整数値を生成しないなど)
  3. エコーをオンにしたときに発行されたSQLが言うこと

1
シェルのクイックチェックでは、主キーフィールドに値が入力されていることがわかります。それが実際に機能しなかった理由を調査する必要があります。
Eloff、

3
「サンプルコードは値を提供する必要がある」というのは、「最初からidの値を指定する必要がある」と言っているように聞こえます。3つ目の読み上げの後でのみ、前者ではなく後者を意味することが明らかになりました。明確にしてもらえますか?
確率論的

126

私はちょうど同じ問題に出くわしました、そしてテストの後、これらの答えのどれも十分ではないことがわかりました。

現在、またはsqlalchemy .6以降では、非常に単純な解決策があります(これが以前のバージョンに存在するかどうかはわかりませんが、あると思います)。

session.refresh()

したがって、コードは次のようになります。

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.

それはそれを行う方法です。


8
これは私にとってはうまくいくかもしれない回答に近づきつつありますが、次のエラーを受け取ります:InvalidRequestError:インスタンス '<....>'を更新できませんでした。フラッシュ後に、インスタンスが存在しなくなったように見えます。洞察を感謝します。
PlaidFan 2011

1
あなたは私のお尻を保存しました。Djangoから再びORMを使用することはないと思います。flush()コマンドは、文書化されたIMHOとして機能しません。
マルク・

2
更新、私はを使用する必要がありましたsessionmaker(autoflush=True)。そのコンボw / refresh()によって行IDが提供されました。#grrr
マルク

5
flush()との違いが理解できない場合はcommit()、良い説明があります。stackoverflow.com
Epoc

2
@PlaidFan flush()使用する代わりに、そのcommit()直後に-で更新しsession.refresh(f)、私のために機能し、SQLAlchemyバージョンを使用します0.6.7
Ricky Levi

20

みんなありがとう。列のマッピングを変更して問題を解決しました。私にとってautoincrement=Trueは必須です。

原点:

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

変更後:

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

その後

session.flush()  
print(f.id)

大丈夫です!


6

dpbの答えとは異なり、更新は必要ありません。フラッシュしたら、idフィールドにアクセスできます。sqlalchemyは、バックエンドで自動生成されたIDを自動的に更新します。

私はこの問題に遭遇し、いくつかの調査の後に正確な理由を理解しました。私のモデルは整数フィールドとしてIDで作成され、私のフォームではIDは非表示フィールドで表されていました(フォームにIDを表示したくなかったため)。非表示フィールドは、デフォルトではテキストとして表されます。widget = hiddenInput())を使用してフォームをintegerfieldに変更すると、問題は解決しました。


1
前述のとおり、refresh()のみが機能しました。データ移行を実行する際、FKに入力するためにループで行IDが必要でした。コミット、フラッシュ、セッションハッキング、refresh()のすべての組み合わせを試してみましたが、機能するのはそれだけでした。私のデータは非常にクリーンであり、SQLAは実際にはそれほど優れていないことがわかりました(少なくとも5つの主要なORMSでかなりの経験がある)。5時間以上ラップして、add()-> commit()/ flush()の行IDを取得しようとしています。
マルク・

1

メソッドを0呼び出す前にidに割り当てることに問題がありましたsession.add。IDはデータベースによって正しく割り当てられましたが、以降のセッションから正しいIDが取得されませんでしたsession.flush()


-7

session.save_or_update(f)代わりに使用してみてくださいsession.add(f)


1
save_or_update0.5以降で廃止されました。session.add()それを行う必要があります。
Pavel Repin
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.