[解決済み] sqlalchemyのback_populatesはいつ使う必要があるのでしょうか?
質問
このガイドに従ってSQLAlchemyのRelation Exampleを試すと、次のようになります。 基本的なリレーションシップのパターン
私はこのようなコードを持っています。
#!/usr/bin/env python
# encoding: utf-8
from sqlalchemy import create_engine
from sqlalchemy import Table, Column, Integer, ForeignKey
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base(bind=engine)
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
children = relationship("Child")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
parent = relationship("Parent")
Base.metadata.create_all()
p = Parent()
session.add(p)
session.commit()
c = Child(parent_id=p.id)
session.add(c)
session.commit()
print "children: {}".format(p.children[0].id)
print "parent: {}".format(c.parent.id)
うまくいくのですが、ガイドでは、モデルはこうあるべきと書いてあります。
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
**children = relationship("Child", back_populates="parent")**
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
**parent = relationship("Parent", back_populates="children")**
なぜ
back_populates
または
backref
のどちらを使うべきでしょうか? どのような場合にどちらかを使うべきでしょうか?
どのように解決するのですか?
もし
backref
を使えば、2つ目のテーブルでリレーションシップを宣言する必要はありません。
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
children = relationship("Child", backref="parent")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
もし、あなたが
ではない
を使って
backref
を定義し、さらに
relationship
を別々に定義した場合、もしあなたが
back_populates
を使わなければ、sqlalchemy はリレーションシップの関係を知らないので、一方を修正すれば他方も修正されます。
ですから、あなたの例で、あなたが
relationship
を別々に定義しているのに対して
back_populates
引数を提供しなかった場合、一方のフィールドを変更しても、トランザクション内のもう一方のフィールドは自動的に更新されません。
>>> parent = Parent()
>>> child = Child()
>>> child.parent = parent
>>> print(parent.children)
[]
を自動的に埋めなかったことを見てみましょう。
children
フィールドを自動的に埋めなかったのがわかりますか?
さて、もしあなたが
back_populates
引数を与えると、sqlalchemyはフィールドを接続します。
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
children = relationship("Child", back_populates="parent")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
parent = relationship("Parent", back_populates="children")
ということで、次は
>>> parent = Parent()
>>> child = Child()
>>> child.parent = parent
>>> print(parent.children)
[Child(...)]
Sqlalchemy はこの2つのフィールドが関連していることを認識し、もう片方が更新されると、それぞれを更新します。 注目すべきは
backref
を使っても同じことができます。 使用方法
back_populates
を使うのは、すべてのクラスでリレーションシップを定義したい場合に便利です。そうすれば、バックリファレンスを通じてフィールドを定義する他のクラスを見る代わりに、モデルクラスをちらっと見るだけですべてのフィールドを簡単に見ることができます。
関連
-
[解決済み] SQLAlchemy ORDER BY DESCENDING?
-
[解決済み] SQLAlchemy: flush() と commit() の違いは何ですか?
-
[解決済み] 前月の日時オブジェクトを返す
-
[解決済み] Pythonのインスタンス変数とクラス変数
-
[解決済み] Django 1.7で初期マイグレーションからマイグレートバックする方法は?
-
[解決済み] Ctrl-CでPythonスクリプトを終了できない
-
[解決済み] Cythonのコードを含むPythonパッケージはどのように構成すればよいのでしょうか?
-
[解決済み] Pandasを使って、既存のExcelファイルに新しいシートを保存する方法は?
-
[解決済み] Pythonでファイルの読み込みと上書きをする
-
[解決済み] pipの依存性/必要条件をリストアップする方法はありますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] PythonでファイルのMD5チェックサムを計算するには?重複
-
[解決済み] Pythonのキャッシュライブラリはありますか?
-
[解決済み] dict を txt ファイルに書き、それを読み取る?
-
[解決済み] Pandasの'Freq'タグにはどのような値が有効ですか?
-
[解決済み] 文字列のリストを内容に基づいてフィルタリングする
-
[解決済み] Pythonで0xを使わずにhex()を使うには?
-
[解決済み] pandasのタイムゾーンに対応したDateTimeIndexを、特定のタイムゾーンに対応したナイーブなタイムスタンプに変換する。
-
[解決済み] Jupyter (IPython)ノートブックのセッションをpickleして保存する方法
-
[解決済み] Python Logging でログメッセージが2回表示される件
-
[解決済み] Flask でグローバル変数はスレッドセーフか?リクエスト間でデータを共有するには?