Release: 2.0.31 | Release Date: June 18, 2024

SQLAlchemy 2.0 Documentation - 私家版日本語訳ドキュメント

SQLAlchemy 2.0 Documentation - 私家版日本語訳ドキュメント

Home

SQLAlchemy Unified Tutorial

  • Establishing Connectivity - the Engine
  • Working with Transactions and the DBAPI
  • Working with Database Metadata
  • Working with Data
  • Data Manipulation with the ORM
  • Working with ORM Related Objects¶
    • Persisting and Loading Relationships
      • Cascading Objects into the Session
    • Loading Relationships
    • Using Relationships in Queries
      • Using Relationships to Join
      • Relationship WHERE Operators
    • Loader Strategies
      • Selectin Load
      • Joined Load
      • Explicit Join + Eager load
      • Raiseload
  • Further Reading

Home

  • Previous: Data Manipulation with the ORM
  • Next: Further Reading
  • Up: Home
    • SQLAlchemy Unified Tutorial
  • On this page:
    • Working with ORM Related Objects
      • Persisting and Loading Relationships
        • Cascading Objects into the Session
      • Loading Relationships
      • Using Relationships in Queries
        • Using Relationships to Join
        • Relationship WHERE Operators
      • Loader Strategies
        • Selectin Load
        • Joined Load
        • Explicit Join + Eager load
        • Raiseload

SQLAlchemy 1.4 / 2.0 Tutorial

このページは SQLAlchemy Unified Tutorial の一部です。

Previous: Data Manipulation with the ORM | Next: Further Reading

Working with ORM Related Objects¶

このセクションでは、ORMが他のオブジェクトを参照するマップされたクラスとどのように相互作用するかという、もう1つの重要なORMの概念について説明します。 Declaring Mapped Classes のセクションで、マップされたクラスの例は relationship() という構成体を使用しています。この構成体は、2つの異なるマップされたクラス間、またはマップされたクラスからそれ自身へのリンクを定義します。後者は**自己参照**関係と呼ばれます。

relationship() の基本的な考え方を説明するために、まず、 mapped_column() のマッピングやその他の指示を省略して、マッピングを短い形式で復習します。:

from sqlalchemy.orm import Mapped
from sqlalchemy.orm import relationship

class User(Base):
    __tablename__ = "user_account"

    # ... mapped_column() mappings

    addresses: Mapped[List["Address"]] = relationship(back_populates="user")

class Address(Base):
    __tablename__ = "address"

    # ... mapped_column() mappings

    user: Mapped["User"] = relationship(back_populates="addresses")

上の例では、 User クラスに User.addresses 属性が追加され、 Address クラスに Address.user 属性が追加されています。 relationship() 構文は、型定義の振る舞いを示す Mapped 構文とともに、 User クラスと Address クラスにマップされた Table オブジェクト間のテーブルの関係を調べるために使用されます。 address テーブルを表す Table オブジェクトは、 user_account テーブルを参照する ForeignKeyConstraint を持っているので、 relationship() は、 User.addresses 関係に沿って、 User クラスから Address クラスへの:term:1対多`の関係があることを明確に判断できます。 ``user_account` テーブルの1つの特定の行は、 address テーブルの多くの行から参照される可能性があります。

すべての1対多の関係は、逆方向の many to one 関係に自然に対応します。この場合は、 Address.user によって示される関係です。上で見たように、他の名前を参照する両方の relationship() オブジェクトに設定された relationship.back_populates パラメータは、これら2つの relationship() 構成体のそれぞれが互いに相補的であると考えるべきであることを確立します。これがどのように行われるかは次のセクションで説明します。

Persisting and Loading Relationships¶

relationship() がオブジェクトのインスタンスに対して何をするかを説明することから始めましょう。新しい User オブジェクトを作成すると、 .addresses 要素にアクセスしたときにPythonのリストがあることがわかります。

>>> u1 = User(name="pkrabs", fullname="Pearl Krabs")
>>> u1.addresses
[]

このオブジェクトはSQLAlchemyに特化したバージョンのPythonの list で、変更を追跡して応答することができます。このコレクションは、属性にアクセスしたときにも自動的に表示されますが、属性をオブジェクトに割り当てたことはありません。これは Inserting Rows using the ORM Unit of Work pattern に記載されている動作と似ています。ここでは、明示的に値を割り当てていない列ベースの属性も、Pythonの通常の動作である AttributeError を発生させるのではなく、自動的に None と表示されることが確認されています。

このコレクションは、その中に永続化できるPythonオブジェクトの唯一の型である Address クラスに固有のものです。 list.append() メソッドを使って、 Address オブジェクトを追加することができます。:

>>> a1 = Address(email_address="pearl.krabs@gmail.com")
>>> u1.addresses.append(a1)

この時点で、予想通り u1.addresses コレクションには新しい Address オブジェクトが含まれています。:

>>> u1.addresses
[Address(id=None, email_address='pearl.krabs@gmail.com')]

この同期は、2つの relationship() オブジェクトの間で relationship.back_populates パラメータを使用した結果として発生しました。このパラメータは、補完的な属性割り当て/リスト変換が発生する別の relationship() を指定します。別の方向でも同様にうまく機能します。つまり、別の Address オブジェクトを作成し、その Address.user 属性に割り当てると、その Address はその User オブジェクトの User.addresses コレクションの一部になります。:

>>> a2 = Address(email_address="pearl@aol.com", user=u1)
>>> u1.addresses
[Address(id=None, email_address='pearl.krabs@gmail.com'), Address(id=None, email_address='pearl@aol.com')]

実際には、 user パラメータを Address コンストラクタのキーワード引数として使用しました。これは、 Address クラスで宣言された他のマップされた属性と同じように受け入れられます。これは、 Address.user 属性を次の事実の後に割り当てるのと同じです。:

# equivalent effect as a2 = Address(user=u1)
>>> a2.user = u1

Cascading Objects into the Session¶

これで、メモリ内の双方向構造体に関連付けられた User オブジェクトと2つの Address オブジェクトができましたが、 Inserting Rows using the ORM Unit of Work pattern で前述したように、これらのオブジェクトは Session オブジェクトに関連付けられるまでは transient 状態にあると言われます。

まだ実行中の Session を利用していますが、 Session.add() メソッドを先頭の User オブジェクトに適用すると、関連する Address オブジェクトも同じ Session に追加されることに注意してください。:

>>> session.add(u1)
>>> u1 in session
True
>>> a1 in session
True
>>> a2 in session
True

Session が`User`オブジェクトを受け取り、関連する`Address`オブジェクトを見つけるために`User.addresses`関係に従った上記の振る舞いは、 save-update カスケード として知られており、 Cascades のORMリファレンス文書で詳細に論じられています。

3つのオブジェクトは pending 状態になっています。これは、これらのオブジェクトがINSERT操作の対象になる準備ができているが、まだ処理されていないことを意味します。3つのオブジェクトはすべて、まだ主キーが割り当てられていません。さらに、 a1 と a2 オブジェクトは、 user_id という属性を持っています。この属性は、 user_account.id 列を参照する ForeignKeyConstraint を持つ Column を参照します。これらのオブジェクトはまだ実際のデータベース行に関連付けられていないので、 None にもなります。:

>>> print(u1.id)
None
>>> print(a1.user_id)
None

作業単位プロセスが提供する非常に大きな有用性を見ることができるのは、この段階です。 INSERT usually generates the “values” clause automatically の節を思い出してください。この節では、 address.user_id 列と user_account 行を自動的に関連付けるために、いくつかの精巧な構文を使って user_account テーブルと address テーブルに行が挿入されました。さらに、 address 行の前に user_account 行に対してINSERTを発行する必要がありました。なぜなら、 address 行の行は user_id 列の値に関して user_account の親行に 依存 しているからです。

Session を使用すると、これらの退屈な作業はすべて私たちのために処理され、最も頑固なSQL純粋主義者でさえ、INSERT、UPDATE、DELETE文の自動化から恩恵を受けることができます。 Session.commit() を使用すると、すべてのステップが正しい順序でトランザクションを呼び出し、さらに新しく生成された user_account 行の主キーが address.user_id 列に適切に適用されます。:

>>> session.commit()
INSERT INTO user_account (name, fullname) VALUES (?, ?) [...] ('pkrabs', 'Pearl Krabs') INSERT INTO address (email_address, user_id) VALUES (?, ?) RETURNING id [... (insertmanyvalues) 1/2 (ordered; batch not supported)] ('pearl.krabs@gmail.com', 6) INSERT INTO address (email_address, user_id) VALUES (?, ?) RETURNING id [insertmanyvalues 2/2 (ordered; batch not supported)] ('pearl@aol.com', 6) COMMIT

Loading Relationships¶

最後のステップでは、 Session.commit() を呼び出してトランザクションのCOMMITを発行し、次に Session.commit.expire_on_commit ごとにすべてのオブジェクトを期限切れにして、次のトランザクションのために更新します。

次にこれらのオブジェクトの属性にアクセスすると、例えば u1 オブジェクトに対して新しく生成されたプライマリ・キーを見るときのように、その行のプライマリ属性に対してSELECTが発行されていることがわかります。

>>> u1.id
BEGIN (implicit) SELECT user_account.id AS user_account_id, user_account.name AS user_account_name, user_account.fullname AS user_account_fullname FROM user_account WHERE user_account.id = ? [...] (6,)
6
>>> u1.addresses
SELECT address.id AS address_id, address.email_address AS address_email_address, address.user_id AS address_user_id FROM address WHERE ? = address.user_id [...] (6,)
[Address(id=4, email_address='pearl.krabs@gmail.com'), Address(id=5, email_address='pearl@aol.com')]

SQLAlchemy ORM内のコレクションと関連する属性はメモリ内に保持されます。コレクションや属性が生成されると、そのコレクションや属性が expired になるまでSQLは生成されなくなります。 u1.addresses に再度アクセスしたり、項目を追加または削除したりすることができますが、これによって新しいSQL呼び出しが発生することはありません:

>>> u1.addresses
[Address(id=4, email_address='pearl.krabs@gmail.com'), Address(id=5, email_address='pearl@aol.com')]

遅延読み込みによって発生する読み込みは、それを最適化するための明示的な手順を実行しなければ、すぐに高価になる可能性がありますが、少なくとも遅延読み込みのネットワークは、冗長な作業を実行しないようにかなり最適化されています。 u1.addresses コレクションが更新されたので、 identity map ごとに、これらは実際には、私たちがすでに扱っている a1 および a2 オブジェクトと同じ Address インスタンスであるため、この特定のオブジェクトグラフのすべての属性の読み込みは完了です:

>>> a1
Address(id=4, email_address='pearl.krabs@gmail.com')
>>> a2
Address(id=5, email_address='pearl@aol.com')

関係がどのようにロードされるかという問題は、それ自体の主題です。これらの概念についての追加の紹介は、このセクションの後半の Loader Strategies にあります。

Using Relationships in Queries¶

前のセクションでは、マップされたクラスの**インスタンス**を扱う場合の relationship() 構文の動作を紹介しました。上では、 User クラスと Address クラスの u1 、 a1 、 a2 インスタンスを紹介しました。このセクションでは、マップされたクラスの クラスレベルの動作 に適用される relationship() の動作を紹介します。このクラスでは、いくつかの方法でSQLクエリの構築を自動化するのに役立ちます。

Using Relationships to Join¶

Explicit FROM clauses and JOINs 節と Setting the ON Clause 節では、SQL JOIN句を作成するための Select.join() メソッドと Select.join_from() メソッドの使用法を紹介しました。テーブル間の結合方法を記述するために、これらのメソッドは、2つのテーブルをリンクするテーブルメタデータ構造内の単一の明白な ForeignKeyConstraint オブジェクトの存在に基づいてON句を**推論**するか、または特定のON句を示す明示的なSQL式構文を提供することができます。

ORMエンティティを使用する場合、結合のON句を設定するのに役立つ追加のメカニズムが利用できます。これは、 Declaring Mapped Classes で示されているように、ユーザマッピングで設定した relationship() オブジェクトを利用することです。 relationship() に対応するclass-bound属性は、 単一の引数 として Select.join() に渡すことができます。この場合、結合の右側とON句の両方を同時に示す役割を果たします:

>>> print(select(Address.email_address).select_from(User).join(User.addresses))
SELECT address.email_address FROM user_account JOIN address ON user_account.id = address.user_id

マッピング上のORM relationship() の存在は、 Select.join() や Select.join_from() では、指定しない場合にON句を推測するために使用されません。つまり、ON句なしで User から Address に結合すると、 User と Address クラスの relationship() オブジェクトではなく、2つのマップされた Table オブジェクト間の ForeignKeyConstraint のために機能します。:

>>> print(select(Address.email_address).join_from(User, Address))
SELECT address.email_address FROM user_account JOIN address ON user_account.id = address.user_id

Select.join() と Select.join_from() を relationship() 構文で使用する方法の例については、 ORM Querying Guide の Joins 節を参照してください。

See also

Joins in the ORM Querying Guide

Relationship WHERE Operators¶

relationship() に付属しているSQL生成ヘルパーには、他にもいくつかの種類があります。これらは通常、文のWHERE句を作成するときに役立ちます。 ORM Querying Guide の Relationship WHERE Operators 節を参照してください。

See also

Relationship WHERE Operators in the ORM Querying Guide

Loader Strategies¶

Loading Relationships 節では、マップされたオブジェクトのインスタンスを操作する際に、デフォルトの場合で relationship() を使ってマップされた属性にアクセスすると、このコレクションに存在するはずのオブジェクトをロードするためにコレクションが作成されていない場合に lazy load が発生するという概念を紹介しました。

遅延読み込みは、最も有名なORMパターンの1つであり、最も物議を醸すパターンでもあります。メモリ内の数十個のORMオブジェクトがそれぞれアンロードされた属性を参照している場合、これらのオブジェクトをルーチンに操作すると、追加される可能性のある多くのクエリがスピンオフされ( N plus one problem としても知られています)、さらに悪いことに、それらは暗黙的に発行されます。これらの暗黙的なクエリは気づかれない可能性があり、利用可能なデータベーストランザクションがなくなった後に試行された場合にエラーを引き起こす可能性があります。また、 asyncio のような別の同時実行パターンを使用している場合には、実際にはまったく動作しません。

同時に、遅延ロードは、使用されている並行性アプローチと互換性があり、他に問題を引き起こさない場合には、非常に一般的で有用なパターンである。これらの理由から、SQLAlchemyのORMは、このロード動作を制御し最適化できることに重点を置いている。

何よりも、ORM遅延読み込みを効果的に使用するための最初のステップは、 アプリケーションをテストし、SQLエコーをオンにし、生成されるSQLを監視する ことです。より効率的に1つにロールできるように見える冗長なSELECT文がたくさんあるように見える場合、 Session から detached されたオブジェクトに対して不適切に発生するロードがある場合、 ローダ戦略 を使用することを検討する必要があります。

ローダー戦略は、 Select.options() メソッドを使用してSELECT文に関連付けられるオブジェクトとして表されます。次に例を示します。:

for user_obj in session.execute(
    select(User).options(selectinload(User.addresses))
).scalars():
    user_obj.addresses  # access addresses collection already loaded

これらは relationship.lazy オプションを使って relationship() のデフォルトとして設定することもできます。:

from sqlalchemy.orm import Mapped
from sqlalchemy.orm import relationship

class User(Base):
    __tablename__ = "user_account"

    addresses: Mapped[List["Address"]] = relationship(
        back_populates="user", lazy="selectin"
    )

それぞれのローダ戦略オブジェクトは、ある種の情報を文に追加します。この情報は、後で Session が様々な属性のロード方法やアクセス時の振る舞いを決定する際に使用されます。

以下のセクションでは、最も顕著に使用されるローダー戦略のいくつかを紹介します。

See also

Relationship Loading Techniques の2つのセクション:

  • Configuring Loader Strategies at Mapping Time - relationship() での戦略の設定に関する詳細

  • Relationship Loading with Loader Options - クエリ時のローダー戦略の詳細

Selectin Load¶

最近のSQLAlchemyで最も便利なローダーは、 selectinload() ローダーオプションです。このオプションは、関連するコレクションを参照するオブジェクトの集合の問題である N+1 問題の最も一般的な形式を解決します。 selectinload() は、完全な一連のオブジェクトの特定のコレクションが単一のクエリを使用して事前にロードされることを保証します。これは、ほとんどの場合、JOINやサブクエリを導入せずに関連するテーブルのみに対して発行でき、コレクションがまだロードされていない親オブジェクトに対するクエリのみに対して発行できるSELECT形式を使用して行われます。以下では、 selectinload() がすべての User オブジェクトとそれに関連するすべての Address オブジェクトをロードすることを説明します。 Session.execute() を一度だけ呼び出しますが、 select() 構文が与えられると、データベースがアクセスされると、実際には2つのSELECT文が発行され、2番目は関連する Address オブジェクトを取得します。

>>> from sqlalchemy.orm import selectinload
>>> stmt = select(User).options(selectinload(User.addresses)).order_by(User.id)
>>> for row in session.execute(stmt):
...     print(
...         f"{row.User.name}  ({', '.join(a.email_address for a in row.User.addresses)})"
...     )
SELECT user_account.id, user_account.name, user_account.fullname FROM user_account ORDER BY user_account.id [...] () SELECT address.user_id AS address_user_id, address.id AS address_id, address.email_address AS address_email_address FROM address WHERE address.user_id IN (?, ?, ?, ?, ?, ?) [...] (1, 2, 3, 4, 5, 6)
spongebob (spongebob@sqlalchemy.org) sandy (sandy@sqlalchemy.org, sandy@squirrelpower.org) patrick () squidward () ehkrabs () pkrabs (pearl.krabs@gmail.com, pearl@aol.com)

See also

Select IN loading - in Relationship Loading Techniques

Joined Load¶

joinedload() のeager load戦略は、SQLAlchemyの中で最も古いeager loaderで、データベースに渡されるSELECT文をJOIN(オプションに応じて外部結合または内部結合)で補強し、関連するオブジェクトにロードすることができます。

joinedload() 戦略は、関連する多対1のオブジェクトをロードするのに最も適しています。なぜなら、これは追加の列が、いかなる場合にもフェッチされるプライマリエンティティ行に追加されることのみを必要とするからです。より効率的にするために、 joinedload.innerjoin オプションも受け入れています。これにより、以下のようにすべての Address オブジェクトに User オブジェクトが関連付けられていることがわかっている場合に、外部結合の代わりに内部結合を使用できます。

>>> from sqlalchemy.orm import joinedload
>>> stmt = (
...     select(Address)
...     .options(joinedload(Address.user, innerjoin=True))
...     .order_by(Address.id)
... )
>>> for row in session.execute(stmt):
...     print(f"{row.Address.email_address} {row.Address.user.name}")
SELECT address.id, address.email_address, address.user_id, user_account_1.id AS id_1, user_account_1.name, user_account_1.fullname FROM address JOIN user_account AS user_account_1 ON user_account_1.id = address.user_id ORDER BY address.id [...] ()
spongebob@sqlalchemy.org spongebob sandy@sqlalchemy.org sandy sandy@squirrelpower.org sandy pearl.krabs@gmail.com pkrabs pearl@aol.com pkrabs

joinedload() はコレクションに対しても機能します。これは一対多の関係を意味しますが、再帰的な方法で関連する項目ごとにプライマリ行を乗算する効果があり、ネストされたコレクションやより大きなコレクションに対して結果セットに送信されるデータの量を桁違いに増加させます。そのため、 selectinload() のような他のオプションと比較して、その使用はケースごとに評価されるべきです。

囲んでいる Select 文 のWHEREおよびORDER BY条件は、joinedload() によって描画されたテーブルを対象にしていないことに注意してください。上記のSQLでは、 匿名のalias がクエリ内で直接アドレス指定できないように user_account テーブルに適用されていることがわかります。この概念については、 The Zen of Joined Eager Loading の節で詳しく説明します。

Tip

“N plus one”問題は一般的なケースではあまり一般的ではないため、多対1のEager Loadは必要ないことが多いことに注意してください。多くのオブジェクトがすべて同じ関連オブジェクトを参照している場合、例えば、それぞれが同じ User を参照している多くの Address オブジェクトの場合、通常の遅延読み込みを使用して、その User オブジェクトに対してSQLが一度だけ生成されます。遅延読み込みルーチンは、可能な限りSQLを生成せずに、現在の Session 内の主キーによって関連オブジェクトを検索します。

See also

Joined Eager Loading - in Relationship Loading Techniques

Explicit Join + Eager load¶

Select.join() などのメソッドを使用してJOINをレンダリングしながら、 user_account テーブルへの結合中に Address 行をロードする場合、返された各 Address オブジェクトの Address.user 属性の内容を積極的にロードするために、そのJOINを利用することもできます。これは基本的に、 結合された積極的なロード を使用していますが、JOIN自体をレンダリングしているということです。この一般的なユースケースは、 contains_eager() オプションを使用することで実現されます。このオプションは joinedload() と非常によく似ていますが、JOIN自体が設定されていることを前提としており、代わりにCOLUMNS句の追加列が返された各オブジェクトの関連する属性にロードされることを示しているだけです。次に例を示します。

>>> from sqlalchemy.orm import contains_eager
>>> stmt = (
...     select(Address)
...     .join(Address.user)
...     .where(User.name == "pkrabs")
...     .options(contains_eager(Address.user))
...     .order_by(Address.id)
... )
>>> for row in session.execute(stmt):
...     print(f"{row.Address.email_address} {row.Address.user.name}")
SELECT user_account.id, user_account.name, user_account.fullname, address.id AS id_1, address.email_address, address.user_id FROM address JOIN user_account ON user_account.id = address.user_id WHERE user_account.name = ? ORDER BY address.id [...] ('pkrabs',)
pearl.krabs@gmail.com pkrabs pearl@aol.com pkrabs

上記では、 user_account.name の行をフィルタし、 user_account の行を返された行の Address.user 属性にロードしました。 joinedload() を別々に適用すると、不必要に2回結合するSQLクエリが得られます:

>>> stmt = (
...     select(Address)
...     .join(Address.user)
...     .where(User.name == "pkrabs")
...     .options(joinedload(Address.user))
...     .order_by(Address.id)
... )
>>> print(stmt)  # SELECT has a JOIN and LEFT OUTER JOIN unnecessarily
SELECT address.id, address.email_address, address.user_id, user_account_1.id AS id_1, user_account_1.name, user_account_1.fullname FROM address JOIN user_account ON user_account.id = address.user_id LEFT OUTER JOIN user_account AS user_account_1 ON user_account_1.id = address.user_id WHERE user_account.name = :name_1 ORDER BY address.id

See also

Two sections in Relationship Loading Techniques:

  • The Zen of Joined Eager Loading - describes the above problem in detail

  • Routing Explicit Joins/Statements into Eagerly Loaded Collections - using contains_eager()

Raiseload¶

特筆すべきもう1つのローダー戦略は raiseload() です。このオプションは、通常は遅延ロードであるものが代わりにエラーを発生させることによって、アプリケーションが N plus one 問題を起こすのを完全にブロックするために使用されます。 raiseload.sql_only オプションで制御される2つのバリエーションがあり、SQLを必要とする遅延ロードと、現在の Session を参照するだけでよいものを含むすべての「ロード」操作のどちらかをブロックします。

raiseload() を使用する1つの方法は、 relationship.lazy を値 raise_on_sql に設定して、 relationship() 自体に設定することです。これにより、特定のマッピングに対して、特定の関係がSQLを出力しようとしなくなります。

:<数値>:
>>> from sqlalchemy.orm import Mapped
>>> from sqlalchemy.orm import relationship
>>> class User(Base):
...     __tablename__ = "user_account"
...     id: Mapped[int] = mapped_column(primary_key=True)
...     addresses: Mapped[List["Address"]] = relationship(
...         back_populates="user", lazy="raise_on_sql"
...     )
>>> class Address(Base):
...     __tablename__ = "address"
...     id: Mapped[int] = mapped_column(primary_key=True)
...     user_id: Mapped[int] = mapped_column(ForeignKey("user_account.id"))
...     user: Mapped["User"] = relationship(back_populates="addresses", lazy="raise_on_sql")

このようなマッピングを使用すると、アプリケーションは遅延読み込みからブロックされ、特定のクエリがローダー戦略を指定する必要があることを示します:

>>> u1 = session.execute(select(User)).scalars().first()
SELECT user_account.id FROM user_account [...] ()
>>> u1.addresses Traceback (most recent call last): ... sqlalchemy.exc.InvalidRequestError: 'User.addresses' is not available due to lazy='raise_on_sql'

この例外は、このコレクションを最初にロードする必要があることを示します。:

>>> u1 = (
...     session.execute(select(User).options(selectinload(User.addresses)))
...     .scalars()
...     .first()
... )
SELECT user_account.id FROM user_account [...] () SELECT address.user_id AS address_user_id, address.id AS address_id FROM address WHERE address.user_id IN (?, ?, ?, ?, ?, ?) [...] (1, 2, 3, 4, 5, 6)

lazy="raise_on_sql"``オプションは、多対1の関係についても賢く扱おうとします。上記では、 ``Address オブジェクトの Address.user 属性がロードされていないが、その User オブジェクトが同じ Session にローカルに存在する場合、”raiseload”戦略はエラーを発生させません。

See also

Preventing unwanted lazy loads using raiseload - in Relationship Loading Techniques

SQLAlchemy 1.4 / 2.0 Tutorial

Next Tutorial Section: Further Reading

Previous: Data Manipulation with the ORM Next: Further Reading
© Copyright 2007-2024, the SQLAlchemy authors and contributors.

flambé! the dragon and The Alchemist image designs created and generously donated by Rotem Yaari.

Created using Sphinx 7.2.6. Documentation last generated: Sat Aug 17 14:19:19 2024 JST