SQLAlchemy 2.0 Dokumentation
SQLAlchemy ORM
- ORM Schnellstart
- ORM Abgebildete Klassenkonfiguration
- Beziehungskonfiguration
- ORM Abfragehandbuch
- Schreiben von SELECT-Anweisungen für ORM-zugeordnete Klassen
- Schreiben von SELECT-Anweisungen für Vererbungszuordnungen
- ORM-aktivierte INSERT-, UPDATE- und DELETE-Anweisungen
- Spaltenladeoptionen
- Relationship Loading Techniques¶
- Zusammenfassung der Beziehungs-Ladestrategien
- Konfiguration von Lader-Strategien zur Abbildungszeit
- Relationship Loading mit Loader-Optionen
- Lazy Loading
- Joined Eager Loading
- Select IN Loading
- Subquery Eager Loading
- Welche Art von Loading soll verwendet werden?
- Polymorphes Eager Loading
- Wildcard Loading Strategies
- Explizite Joins/Statements in Eagerly Loaded Collections leiten
- Relationship Loader API
contains_eager()defaultload()immediateload()joinedload()lazyload()LoadLoad.contains_eager()Load.defaultload()Load.defer()Load.get_children()Load.immediateload()Load.inherit_cacheLoad.joinedload()Load.lazyload()Load.load_only()Load.noload()Load.options()Load.process_compile_state()Load.process_compile_state_replaced_entities()Load.propagate_to_loadersLoad.raiseload()Load.selectin_polymorphic()Load.selectinload()Load.subqueryload()Load.undefer()Load.undefer_group()Load.with_expression()
noload()raiseload()selectinload()subqueryload()
- ORM-API-Funktionen für Abfragen
- Legacy Query API
- Verwendung der Sitzung
- Ereignisse und Interna
- ORM Erweiterungen
- ORM Beispiele
Projektversionen
- Vorheriger: Column Loading Options
- Nächster: ORM API Features for Querying
- Oben: Startseite
- Auf dieser Seite
- Techniken für das Laden von Beziehungen
- Zusammenfassung der Beziehungs-Ladestrategien
- Konfiguration von Lader-Strategien zur Abbildungszeit
- Relationship Loading mit Loader-Optionen
- Lazy Loading
- Joined Eager Loading
- Select IN Loading
- Subquery Eager Loading
- Welche Art von Loading soll verwendet werden?
- Polymorphes Eager Loading
- Wildcard Loading Strategies
- Explizite Joins/Statements in Eagerly Loaded Collections leiten
- Relationship Loader API
contains_eager()defaultload()immediateload()joinedload()lazyload()LoadLoad.contains_eager()Load.defaultload()Load.defer()Load.get_children()Load.immediateload()Load.inherit_cacheLoad.joinedload()Load.lazyload()Load.load_only()Load.noload()Load.options()Load.process_compile_state()Load.process_compile_state_replaced_entities()Load.propagate_to_loadersLoad.raiseload()Load.selectin_polymorphic()Load.selectinload()Load.subqueryload()Load.undefer()Load.undefer_group()Load.with_expression()
noload()raiseload()selectinload()subqueryload()
Relationship Loading Techniques¶
Über dieses Dokument
Dieser Abschnitt gibt einen detaillierten Einblick, wie verwandte Objekte geladen werden. Leser sollten mit Relationship Configuration und grundlegender Verwendung vertraut sein.
Die meisten Beispiele hier setzen das "User/Address"-Abbildungsschema voraus, ähnlich dem, das unter setup for selects dargestellt ist.
Ein großer Teil von SQLAlchemy besteht darin, eine breite Palette von Kontrolle darüber zu bieten, wie verwandte Objekte beim Abfragen geladen werden. Mit "verwandten Objekten" meinen wir Sammlungen oder Skalar-Assoziationen, die auf einem Mapper mit relationship() konfiguriert wurden. Dieses Verhalten kann zur Abbildungszeit über den Parameter relationship.lazy zur Funktion relationship() konfiguriert werden, sowie durch die Verwendung von ORM Loader Options mit dem Select-Konstrukt.
Das Laden von Beziehungen fällt in drei Kategorien: lazy loading, eager loading und no loading. Lazy loading bezieht sich auf Objekte, die aus einer Abfrage zurückgegeben werden, ohne dass die zugehörigen Objekte zunächst geladen wurden. Wenn auf die gegebene Sammlung oder Referenz auf einem bestimmten Objekt zum ersten Mal zugegriffen wird, wird eine zusätzliche SELECT-Anweisung ausgegeben, sodass die angeforderte Sammlung geladen wird.
Eager loading bezieht sich auf Objekte, die aus einer Abfrage zurückgegeben werden, wobei die zugehörige Sammlung oder Skalarreferenz bereits im Voraus geladen wurde. Die ORM erreicht dies entweder durch Ergänzung der SELECT-Anweisung, die sie normalerweise ausgeben würde, mit einem JOIN, um verwandte Zeilen gleichzeitig zu laden, oder durch Ausgabe zusätzlicher SELECT-Anweisungen nach der primären, um Sammlungen oder Skalarreferenzen auf einmal zu laden.
"No" loading bezieht sich auf das Deaktivieren des Ladens einer bestimmten Beziehung, entweder dass das Attribut leer ist und nie geladen wird, oder dass beim Zugriff darauf ein Fehler ausgelöst wird, um unerwünschte Lazy Loads zu vermeiden.
Zusammenfassung der Beziehungs-Ladestrategien¶
Die primären Formen des Relationship Loading sind:
lazy loading - verfügbar über
lazy='select'oder die Optionlazyload(). Dies ist die Form des Ladens, die beim Zugreifen auf ein Attribut eine SELECT-Anweisung ausgibt, um eine verwandte Referenz für ein einzelnes Objekt nachzuladen. Lazy loading ist der Standard-Ladestil für allerelationship()-Konstrukte, die nicht anderweitig die Optionrelationship.lazyangeben. Lazy loading wird unter Lazy Loading detailliert beschrieben.select IN loading - verfügbar über
lazy='selectin'oder die Optionselectinload(). Diese Ladeform gibt eine zweite (oder mehr) SELECT-Anweisung aus, die die Primärschlüssel-Identifikatoren der übergeordneten Objekte in einer IN-Klausel zusammenfasst, so dass alle Mitglieder der verwandten Sammlungen/Skalarreferenzen auf einmal nach Primärschlüssel geladen werden. Select IN loading wird unter Select IN loading detailliert beschrieben.joined loading - verfügbar über
lazy='joined'oder die Optionjoinedload(). Diese Ladeform wendet einen JOIN auf die gegebene SELECT-Anweisung an, so dass verwandte Zeilen im selben Ergebnis-Set geladen werden. Joined eager loading wird unter Joined Eager Loading detailliert beschrieben.raise loading - verfügbar über
lazy='raise',lazy='raise_on_sql', oder die Optionraiseload(). Diese Ladeform wird zur gleichen Zeit ausgelöst, zu der ein Lazy Load normalerweise auftreten würde, aber sie löst eine ORM-Exception aus, um die Anwendung unerwünschter Lazy Loads zu verhindern. Eine Einführung in Raise Loading finden Sie unter Preventing unwanted lazy loads using raiseload.subquery loading - verfügbar über
lazy='subquery'oder die Optionsubqueryload(). Diese Ladeform gibt eine zweite SELECT-Anweisung aus, die die ursprüngliche Abfrage in einer Subquery neu formuliert und diese Subquery dann mit der zu ladenden zugehörigen Tabelle verbindet, um alle Mitglieder verwandter Sammlungen/Skalarreferenzen auf einmal zu laden. Subquery eager loading wird unter Subquery Eager Loading detailliert beschrieben.write only loading - verfügbar über
lazy='write_only', oder durch Annotation der linken Seite desRelationship-Objekts mittels der AnnotationWriteOnlyMapped. Dieser reine Sammlungs-Loader-Stil erzeugt eine alternative Attributinstrumentierung, die niemals implizit Datensätze aus der Datenbank lädt, sondern nur die MethodenWriteOnlyCollection.add(),WriteOnlyCollection.add_all()undWriteOnlyCollection.remove()zulässt. Das Abfragen der Sammlung erfolgt durch Aufrufen einer SELECT-Anweisung, die mit der MethodeWriteOnlyCollection.select()erstellt wird. Write-only loading wird unter Write Only Relationships besprochen.dynamic loading - verfügbar über
lazy='dynamic', oder durch Annotation der linken Seite desRelationship-Objekts mittels der AnnotationDynamicMapped. Dies ist ein älterer Sammlungs-spezifischer Lader-Stil, der einQuery-Objekt erzeugt, wenn auf die Sammlung zugegriffen wird, was die Ausgabe benutzerdefinierter SQL-Abfragen für den Inhalt der Sammlung ermöglicht. Dynamische Loader iterieren jedoch unter verschiedenen Umständen implizit die zugrunde liegende Sammlung, was sie für die Verwaltung wirklich großer Sammlungen weniger nützlich macht. Dynamische Loader werden durch „write only“-Sammlungen abgelöst, die verhindern, dass die zugrunde liegende Sammlung unter keinen Umständen implizit geladen wird. Dynamische Loader werden unter Dynamic Relationship Loaders besprochen.
Konfiguration von Lader-Strategien zur Abbildungszeit¶
Die Laderstrategie für eine bestimmte Beziehung kann zur Abbildungszeit so konfiguriert werden, dass sie in allen Fällen stattfindet, in denen ein Objekt des abgebildeten Typs geladen wird, sofern keine Abfrageebenenoptionen vorliegen, die sie modifizieren. Dies wird über den Parameter relationship.lazy zur Funktion relationship() konfiguriert; übliche Werte für diesen Parameter sind select, selectin und joined.
Das folgende Beispiel veranschaulicht das Beziehungsexempel unter One To Many, bei dem die Beziehung Parent.children so konfiguriert wird, dass sie Select IN loading verwendet, wenn eine SELECT-Anweisung für Parent-Objekte ausgegeben wird.
from typing import List
from sqlalchemy import ForeignKey
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
class Base(DeclarativeBase):
pass
class Parent(Base):
__tablename__ = "parent"
id: Mapped[int] = mapped_column(primary_key=True)
children: Mapped[List["Child"]] = relationship(lazy="selectin")
class Child(Base):
__tablename__ = "child"
id: Mapped[int] = mapped_column(primary_key=True)
parent_id: Mapped[int] = mapped_column(ForeignKey("parent.id"))Oben wird, wann immer eine Sammlung von Parent-Objekten geladen wird, jedes Parent auch seine children-Sammlung gefüllt haben, unter Verwendung der "selectin"-Laderstrategie, die eine zweite Abfrage ausgibt.
Der Standardwert des Arguments relationship.lazy ist "select", was Lazy Loading bedeutet.
Relationship Loading mit Loader Options¶
Der andere, und vielleicht gebräuchlichere Weg, Lade-Strategien zu konfigurieren, ist, sie auf einer Pro-Abfrage-Basis gegen spezifische Attribute über die Methode Select.options() einzurichten. Sehr detaillierte Kontrolle über das Relationship Loading ist über Loader Options verfügbar; die gebräuchlichsten sind joinedload(), selectinload() und lazyload(). Die Option akzeptiert ein klassengebundenes Attribut, das die spezifische Klasse/Attribut referenziert, auf die gezielt werden soll.
from sqlalchemy import select
from sqlalchemy.orm import lazyload
# set children to load lazily
stmt = select(Parent).options(lazyload(Parent.children))
from sqlalchemy.orm import joinedload
# set children to load eagerly with a join
stmt = select(Parent).options(joinedload(Parent.children))Die Loader-Optionen können auch über Method Chaining "verkettet" werden, um anzugeben, wie das Laden auf tieferen Ebenen erfolgen soll.
from sqlalchemy import select
from sqlalchemy.orm import joinedload
stmt = select(Parent).options(
joinedload(Parent.children).subqueryload(Child.subelements)
)Verkettete Loader-Optionen können auf eine "lazy" geladene Sammlung angewendet werden. Das bedeutet, dass, wenn eine Sammlung oder Assoziation beim Zugriff lazy geladen wird, die angegebene Option wirksam wird.
from sqlalchemy import select
from sqlalchemy.orm import lazyload
stmt = select(Parent).options(lazyload(Parent.children).subqueryload(Child.subelements))Oben wird die Abfrage Parent-Objekte zurückgeben, ohne dass die children-Sammlungen geladen wurden. Wenn zum ersten Mal auf die children-Sammlung eines bestimmten Parent-Objekts zugegriffen wird, werden die zugehörigen Objekte lazy geladen, aber zusätzlich wird das Eager Loading auf die subelements-Sammlung jedes Mitglieds von children angewendet.
Hinzufügen von Kriterien zu Loader-Optionen¶
Die für die Angabe von Loader-Optionen verwendeten Beziehungsattribute beinhalten die Möglichkeit, zusätzliche Filterkriterien zur ON-Klausel des erstellten Joins oder zu den WHERE-Kriterien hinzuzufügen, je nach Lader-Strategie. Dies kann über die Methode PropComparator.and_() erreicht werden, die eine Option weitergibt, so dass die geladenen Ergebnisse auf die angegebenen Filterkriterien beschränkt werden.
from sqlalchemy import select
from sqlalchemy.orm import lazyload
stmt = select(A).options(lazyload(A.bs.and_(B.id > 5)))Bei Verwendung von Limitierungskriterien wird eine bereits geladene Sammlung nicht erneut aktualisiert. Um sicherzustellen, dass die neuen Kriterien wirksam werden, wenden Sie die Ausführungsoption Populate Existing an.
from sqlalchemy import select
from sqlalchemy.orm import lazyload
stmt = (
select(A)
.options(lazyload(A.bs.and_(B.id > 5)))
.execution_options(populate_existing=True)
)Um Filterkriterien zu allen Vorkommen einer Entität in einer Abfrage hinzuzufügen, unabhängig von der Laderstrategie oder wo sie im Ladevorgang auftritt, siehe die Funktion with_loader_criteria().
Neu in Version 1.4.
Spezifikation von Unteroptionen mit Load.options()¶
Durch Method Chaining wird der Lade-Stil jedes Links im Pfad explizit angegeben. Um einen Pfad zu durchlaufen, ohne den bestehenden Lade-Stil eines bestimmten Attributs zu ändern, kann die Methode/Funktion defaultload() verwendet werden.
from sqlalchemy import select
from sqlalchemy.orm import defaultload
stmt = select(A).options(defaultload(A.atob).joinedload(B.btoc))Ein ähnlicher Ansatz kann verwendet werden, um mehrere Unteroptionen gleichzeitig anzugeben, mithilfe der Methode Load.options().
from sqlalchemy import select
from sqlalchemy.orm import defaultload
from sqlalchemy.orm import joinedload
stmt = select(A).options(
defaultload(A.atob).options(joinedload(B.btoc), joinedload(B.btod))
)Siehe auch
Using load_only() on related objects and collections - illustriert Beispiele für die Kombination von relationalen und spaltenorientierten Laderoptionen.
Hinweis
Die auf die Lazy-Loaded-Sammlungen eines Objekts angewendeten Laderoptionen sind "sticky" für bestimmte Objektinstanzen, was bedeutet, dass sie für Sammlungen, die von diesem spezifischen Objekt geladen wurden, so lange bestehen bleiben, wie es im Speicher vorhanden ist. Gegeben sei beispielsweise das vorherige Beispiel:
stmt = select(Parent).options(lazyload(Parent.children).subqueryload(Child.subelements))Wenn die children-Sammlung eines bestimmten Parent-Objekts, das durch die obige Abfrage geladen wurde, abgelaufen ist (z. B. wenn die Transaktion eines Session-Objekts committed oder zurückgerollt wird, oder Session.expire_all() verwendet wird), dann wird beim nächsten Zugriff auf die Parent.children-Sammlung, um sie neu zu laden, die Child.subelements-Sammlung erneut über Subquery Eager Loading geladen. Dies bleibt auch dann bestehen, wenn das obige Parent-Objekt aus einer nachfolgenden Abfrage abgerufen wird, die einen anderen Satz von Optionen angibt. Um die Optionen auf einem vorhandenen Objekt zu ändern, ohne es zu entladen und neu zu laden, müssen sie explizit in Kombination mit der Ausführungsoption Populate Existing gesetzt werden.
# change the options on Parent objects that were already loaded
stmt = (
select(Parent)
.execution_options(populate_existing=True)
.options(lazyload(Parent.children).lazyload(Child.subelements))
.all()
)Wenn die oben geladenen Objekte vollständig aus der Session entfernt werden, z. B. durch Garbage Collection oder wenn Session.expunge_all() verwendet wurde, sind die "sticky"-Optionen ebenfalls weg und die neu erstellten Objekte werden bei erneutem Laden neue Optionen verwenden.
Eine zukünftige SQLAlchemy-Version kann mehr Alternativen zur Manipulation der Laderoptionen auf bereits geladenen Objekten hinzufügen.
Lazy Loading¶
Standardmäßig sind alle Beziehungen zwischen Objekten lazy loading. Das Skalar- oder Sammlungsattribut, das mit einem relationship() verbunden ist, enthält einen Auslöser, der beim ersten Zugriff auf das Attribut ausgelöst wird. Dieser Auslöser gibt in der Regel einen SQL-Aufruf zum Zeitpunkt des Zugriffs aus, um das oder die zugehörigen Objekte zu laden.
>>> spongebob.addresses
SELECT
addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id
FROM addresses
WHERE ? = addresses.user_id
[5]
[<Address(u'spongebob@google.com')>, <Address(u'j25@yahoo.com')>]Der einzige Fall, in dem kein SQL ausgegeben wird, ist eine einfache Many-to-One-Beziehung, wenn das zugehörige Objekt allein durch seinen Primärschlüssel identifiziert werden kann und dieses Objekt bereits in der aktuellen Session vorhanden ist. Aus diesem Grund kann, während Lazy Loading für zugehörige Sammlungen teuer sein kann, im Falle, dass man viele Objekte mit einfachen Many-to-Ones gegen eine relativ kleine Menge möglicher Zielobjekte lädt, Lazy Loading auf diese Objekte lokal verweisen, ohne so viele SELECT-Anweisungen auszugeben, wie es übergeordnete Objekte gibt.
Dieses Standardverhalten des "Ladens beim Attributzugriff" wird als "lazy" oder "select" loading bezeichnet – "select", weil typischerweise eine "SELECT"-Anweisung ausgegeben wird, wenn zuerst auf das Attribut zugegriffen wird.
Lazy loading kann für ein gegebenes Attribut aktiviert werden, das normalerweise auf andere Weise konfiguriert ist, mithilfe der Laderoption lazyload().
from sqlalchemy import select
from sqlalchemy.orm import lazyload
# force lazy loading for an attribute that is set to
# load some other way normally
stmt = select(User).options(lazyload(User.addresses))Verhindern unerwünschter Lazy Loads mit raiseload¶
Die Strategie lazyload() erzeugt einen Effekt, der eines der häufigsten Probleme im Object-Relational Mapping ist; das N plus one problem, das besagt, dass bei N geladenen Objekten der Zugriff auf ihre lazy geladenen Attribute bedeutet, dass N+1 SELECT-Anweisungen ausgegeben werden. In SQLAlchemy ist die übliche Abmilderung des N+1-Problems die Nutzung seines sehr leistungsfähigen Eager-Load-Systems. Eager Loading erfordert jedoch, dass die zu ladenden Attribute im Select im Voraus angegeben werden. Das Problem von Code, der auf andere Attribute zugreift, die nicht eager geladen wurden, und wo Lazy Loading nicht gewünscht ist, kann mit der Strategie raiseload() gelöst werden; diese Laderstrategie ersetzt das Verhalten des Lazy Loading durch Auslösen einer informativen Fehlermeldung.
from sqlalchemy import select
from sqlalchemy.orm import raiseload
stmt = select(User).options(raiseload(User.addresses))Oben wird ein User-Objekt, das aus der obigen Abfrage geladen wurde, die .addresses-Sammlung nicht geladen haben; wenn später versucht wird, auf dieses Attribut zuzugreifen, wird eine ORM-Exception ausgelöst.
raiseload() kann mit einem sogenannten "Wildcard"-Spezifizierer verwendet werden, um anzugeben, dass alle Beziehungen diese Strategie verwenden sollen. Zum Beispiel, um nur ein Attribut als Eager-Loading einzurichten und alle anderen als Raise:
from sqlalchemy import select
from sqlalchemy.orm import joinedload
from sqlalchemy.orm import raiseload
stmt = select(Order).options(joinedload(Order.items), raiseload("*"))Der obige Wildcard gilt für alle Beziehungen, nicht nur für Order außer items, sondern auch für alle Beziehungen auf den Item-Objekten. Um raiseload() nur für die Order-Objekte einzurichten, geben Sie einen vollständigen Pfad mit Load an.
from sqlalchemy import select
from sqlalchemy.orm import joinedload
from sqlalchemy.orm import Load
stmt = select(Order).options(joinedload(Order.items), Load(Order).raiseload("*"))Umgekehrt, um Raise nur für die Item-Objekte einzurichten:
stmt = select(Order).options(joinedload(Order.items).raiseload("*"))Die Option raiseload() gilt nur für Beziehungsattribute. Für spaltenorientierte Attribute unterstützt die Option defer() die Option defer.raiseload, die auf ähnliche Weise funktioniert.
Tipp
Die "raiseload"-Strategien gelten nicht während des Flush-Prozesses der Unit of Work. Das bedeutet, wenn der Session.flush()-Prozess eine Sammlung laden muss, um seine Arbeit abzuschließen, wird er dies tun, während raiseload()-Direktiven umgangen werden.
Joined Eager Loading¶
Joined eager loading ist der älteste Eager-Loading-Stil, der in der SQLAlchemy ORM enthalten ist. Er funktioniert, indem ein JOIN (standardmäßig ein LEFT OUTER JOIN) zur ausgegebenen SELECT-Anweisung verbunden wird und das Ziel-Skalar/Sammlung aus demselben Ergebnis-Set wie das des übergeordneten Elements gefüllt wird.
Auf Abbildungsebene sieht das so aus:
class Address(Base):
# ...
user: Mapped[User] = relationship(lazy="joined")Joined eager loading wird normalerweise als Option zu einer Abfrage verwendet, anstatt als Standard-Ladeoption in der Abbildung, insbesondere wenn es für Sammlungen und nicht für Many-to-One-Referenzen verwendet wird. Dies geschieht über die Laderoption joinedload().
>>> from sqlalchemy import select
>>> from sqlalchemy.orm import joinedload
>>> stmt = select(User).options(joinedload(User.addresses)).filter_by(name="spongebob")
>>> spongebob = session.scalars(stmt).unique().all()
SELECT
addresses_1.id AS addresses_1_id,
addresses_1.email_address AS addresses_1_email_address,
addresses_1.user_id AS addresses_1_user_id,
users.id AS users_id, users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
LEFT OUTER JOIN addresses AS addresses_1
ON users.id = addresses_1.user_id
WHERE users.name = ?
['spongebob']
Tipp
Wenn joinedload() in Bezug auf eine One-to-Many- oder Many-to-Many-Sammlung enthalten ist, muss die Methode Result.unique() auf das zurückgegebene Ergebnis angewendet werden, was die eingehenden Zeilen nach Primärschlüssel eindeutig macht, die ansonsten durch den Join vervielfältigt werden. Die ORM löst einen Fehler aus, wenn dies nicht vorhanden ist.
Dies ist in modernem SQLAlchemy nicht mehr automatisch, da es das Verhalten des Ergebnis-Sets ändert, um weniger ORM-Objekte zurückzugeben, als die Anweisung normalerweise in Bezug auf die Anzahl der Zeilen zurückgeben würde. Daher hält SQLAlchemy die Verwendung von Result.unique() explizit, so dass keine Mehrdeutigkeit besteht, dass die zurückgegebenen Objekte nach Primärschlüssel eindeutig gemacht werden.
Der standardmäßig ausgegebene JOIN ist ein LEFT OUTER JOIN, um ein führendes Objekt zu ermöglichen, das sich nicht auf eine zugehörige Zeile bezieht. Für ein Attribut, das garantiert ein Element hat, wie z. B. eine Many-to-One-Referenz auf ein zugehöriges Objekt, bei dem der referenzierende Fremdschlüssel NICHT NULL ist, kann die Abfrage effizienter gemacht werden, indem ein innerer Join verwendet wird; dies ist auf Abbildungsebene über das Flag relationship.innerjoin verfügbar.
class Address(Base):
# ...
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
user: Mapped[User] = relationship(lazy="joined", innerjoin=True)Auf der Ebene der Abfrageoptionen, über das Flag joinedload.innerjoin.
from sqlalchemy import select
from sqlalchemy.orm import joinedload
stmt = select(Address).options(joinedload(Address.user, innerjoin=True))Der JOIN wird sich "right-nesten", wenn er in einer Kette angewendet wird, die einen OUTER JOIN enthält.
>>> from sqlalchemy import select
>>> from sqlalchemy.orm import joinedload
>>> stmt = select(User).options(
... joinedload(User.addresses).joinedload(Address.widgets, innerjoin=True)
... )
>>> results = session.scalars(stmt).unique().all()
SELECT
widgets_1.id AS widgets_1_id,
widgets_1.name AS widgets_1_name,
addresses_1.id AS addresses_1_id,
addresses_1.email_address AS addresses_1_email_address,
addresses_1.user_id AS addresses_1_user_id,
users.id AS users_id, users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
LEFT OUTER JOIN (
addresses AS addresses_1 JOIN widgets AS widgets_1 ON
addresses_1.widget_id = widgets_1.id
) ON users.id = addresses_1.user_id
Tipp
Wenn Datenbankzeilen-Sperrtechniken beim Ausgeben der SELECT-Anweisung verwendet werden, d. h. die Methode Select.with_for_update() verwendet wird, um SELECT..FOR UPDATE auszugeben, kann auch die verknüpfte Tabelle gesperrt werden, abhängig vom Verhalten des verwendeten Backends. Aus diesem Grund wird die Verwendung von Joined Eager Loading zusammen mit SELECT..FOR UPDATE nicht empfohlen.
Der Zen des Joined Eager Loading¶
Da Joined Eager Loading viele Ähnlichkeiten mit der Verwendung von Select.join() aufweist, führt dies oft zu Verwirrung darüber, wann und wie es verwendet werden sollte. Es ist entscheidend zu verstehen, dass, während Select.join() verwendet wird, um die Ergebnisse einer Abfrage zu ändern, joinedload() große Anstrengungen unternimmt, um die Ergebnisse der Abfrage nicht zu ändern, und stattdessen die Auswirkungen des gerenderten Joins ausblendet, um nur das Vorhandensein verwandter Objekte zu ermöglichen.
Die Philosophie hinter Lade-Strategien ist, dass jede beliebige Menge von Ladeschemata auf eine bestimmte Abfrage angewendet werden kann und sich die Ergebnisse nicht ändern – nur die Anzahl der SQL-Anweisungen, die zum vollständigen Laden verwandter Objekte und Sammlungen erforderlich sind, ändert sich. Eine bestimmte Abfrage könnte ursprünglich mit allen Lazy-Loads beginnen. Nach der Verwendung im Kontext könnte sich herausstellen, dass bestimmte Attribute oder Sammlungen immer aufgerufen werden und es effizienter wäre, die Lade-Strategie dafür zu ändern. Die Strategie kann ohne weitere Änderungen an der Abfrage geändert werden, die Ergebnisse bleiben identisch, aber es würden weniger SQL-Anweisungen ausgegeben. Theoretisch (und praktisch gesehen) kann nichts, was Sie mit dem Select tun, dazu führen, dass es eine andere Menge von primären oder verwandten Objekten basierend auf einer Änderung der Lade-Strategie lädt.
Wie joinedload() insbesondere dieses Ergebnis erzielt, keine Auswirkungen auf die zurückgegebenen Entitätszeilen zu haben, besteht darin, dass eine anonyme Aliasbildung der Joins erstellt wird, die zu Ihrer Abfrage hinzugefügt werden, sodass sie von anderen Teilen der Abfrage nicht referenziert werden können. Zum Beispiel verwendet die untenstehende Abfrage joinedload(), um einen LEFT OUTER JOIN von users zu addresses zu erstellen. Allerdings ist die ORDER BY, die auf Address.email_address angewendet wird, ungültig – die Address-Entität ist in der Abfrage nicht benannt.
>>> from sqlalchemy import select
>>> from sqlalchemy.orm import joinedload
>>> stmt = (
... select(User)
... .options(joinedload(User.addresses))
... .filter(User.name == "spongebob")
... .order_by(Address.email_address)
... )
>>> result = session.scalars(stmt).unique().all()
SELECT
addresses_1.id AS addresses_1_id,
addresses_1.email_address AS addresses_1_email_address,
addresses_1.user_id AS addresses_1_user_id,
users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
LEFT OUTER JOIN addresses AS addresses_1
ON users.id = addresses_1.user_id
WHERE users.name = ?
ORDER BY addresses.email_address <-- this part is wrong !
['spongebob']
Oben ist ORDER BY addresses.email_address ungültig, da addresses nicht in der FROM-Liste steht. Der korrekte Weg, die User-Datensätze zu laden und nach E-Mail-Adresse zu sortieren, ist die Verwendung von Select.join().
>>> from sqlalchemy import select
>>> stmt = (
... select(User)
... .join(User.addresses)
... .filter(User.name == "spongebob")
... .order_by(Address.email_address)
... )
>>> result = session.scalars(stmt).unique().all()
SELECT
users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
JOIN addresses ON users.id = addresses.user_id
WHERE users.name = ?
ORDER BY addresses.email_address
['spongebob']
Die obige Anweisung ist natürlich nicht dieselbe wie die vorherige, da die Spalten von addresses überhaupt nicht im Ergebnis enthalten sind. Wir können joinedload() wieder hinzufügen, so dass es zwei Joins gibt – einer ist der, nach dem wir sortieren, der andere wird anonym verwendet, um den Inhalt der User.addresses-Sammlung zu laden.
>>> stmt = (
... select(User)
... .join(User.addresses)
... .options(joinedload(User.addresses))
... .filter(User.name == "spongebob")
... .order_by(Address.email_address)
... )
>>> result = session.scalars(stmt).unique().all()
SELECT
addresses_1.id AS addresses_1_id,
addresses_1.email_address AS addresses_1_email_address,
addresses_1.user_id AS addresses_1_user_id,
users.id AS users_id, users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users JOIN addresses
ON users.id = addresses.user_id
LEFT OUTER JOIN addresses AS addresses_1
ON users.id = addresses_1.user_id
WHERE users.name = ?
ORDER BY addresses.email_address
['spongebob']
Was wir oben sehen, ist, dass unsere Verwendung von Select.join() dazu dient, JOIN-Klauseln bereitzustellen, die wir in nachfolgenden Abfragekriterien verwenden möchten, während sich unsere Verwendung von joinedload() nur auf das Laden der User.addresses-Sammlung für jeden User im Ergebnis konzentriert. In diesem Fall sind die beiden Joins höchstwahrscheinlich redundant – was sie auch sind. Wenn wir nur einen JOIN für die Sammlungsladung sowie für die Sortierung verwenden möchten, verwenden wir die Option contains_eager(), die weiter unten unter Routing von expliziten Joins/Anweisungen in eager geladene Sammlungen beschrieben wird. Aber um zu verstehen, warum joinedload() das tut, was es tut, betrachten wir den Fall, wenn wir nach einer bestimmten Address **filtern**.
>>> stmt = (
... select(User)
... .join(User.addresses)
... .options(joinedload(User.addresses))
... .filter(User.name == "spongebob")
... .filter(Address.email_address == "someaddress@foo.com")
... )
>>> result = session.scalars(stmt).unique().all()
SELECT
addresses_1.id AS addresses_1_id,
addresses_1.email_address AS addresses_1_email_address,
addresses_1.user_id AS addresses_1_user_id,
users.id AS users_id, users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users JOIN addresses
ON users.id = addresses.user_id
LEFT OUTER JOIN addresses AS addresses_1
ON users.id = addresses_1.user_id
WHERE users.name = ? AND addresses.email_address = ?
['spongebob', 'someaddress@foo.com']
Oben sehen wir, dass die beiden JOINs sehr unterschiedliche Rollen spielen. Einer wird genau eine Zeile abgleichen, nämlich den Join von User und Address, bei dem Address.email_address=='someaddress@foo.com' ist. Der andere LEFT OUTER JOIN wird *alle* Address-Zeilen abgleichen, die mit User in Beziehung stehen, und wird nur zum Befüllen der User.addresses-Sammlung für die zurückgegebenen User-Objekte verwendet.
Durch Ändern der Verwendung von joinedload() in einen anderen Ladestil können wir ändern, wie die Sammlung vollständig unabhängig von der SQL geladen wird, die zum Abrufen der tatsächlichen User-Zeilen verwendet wird, die wir wollen. Unten ändern wir joinedload() in selectinload().
>>> stmt = (
... select(User)
... .join(User.addresses)
... .options(selectinload(User.addresses))
... .filter(User.name == "spongebob")
... .filter(Address.email_address == "someaddress@foo.com")
... )
>>> result = session.scalars(stmt).all()
SELECT
users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
JOIN addresses ON users.id = addresses.user_id
WHERE
users.name = ?
AND addresses.email_address = ?
['spongebob', 'someaddress@foo.com']
# ... selectinload() emits a SELECT in order
# to load all address records ...
Bei der Verwendung von Joined Eager Loading, wenn die Abfrage einen Modifikator enthält, der die zurückgegebenen Zeilen extern zu den Joins beeinflusst, wie z. B. bei der Verwendung von DISTINCT, LIMIT, OFFSET oder Äquivalenten, wird die abgeschlossene Anweisung zuerst in eine Unterabfrage eingeschlossen und die speziell für Joined Eager Loading verwendeten Joins werden auf die Unterabfrage angewendet. SQLAlchemy's Joined Eager Loading geht die Extrameile und dann noch zehn Meilen weiter, um absolut sicherzustellen, dass das Endergebnis der Abfrage nicht beeinträchtigt wird, sondern nur die Art und Weise, wie Sammlungen und verwandte Objekte geladen werden, unabhängig vom Format der Abfrage.
Siehe auch
Routing von expliziten Joins/Anweisungen in eager geladene Sammlungen – Verwendung von contains_eager()
Select IN Loading¶
In den meisten Fällen ist Selectin Loading der einfachste und effizienteste Weg, Sammlungen von Objekten eager zu laden. Das einzige Szenario, in dem Selectin Eager Loading nicht praktikabel ist, ist, wenn das Modell zusammengesetzte Primärschlüssel verwendet und die zugrunde liegende Datenbank keine Tupel mit IN unterstützt, was derzeit SQL Server einschließt.
"Select IN" Eager Loading wird über das Argument "selectin" für relationship.lazy oder über die Loader-Option selectinload() bereitgestellt. Dieser Ladestil gibt eine SELECT-Anweisung aus, die auf die Primärschlüsselwerte des Elternobjekts verweist oder im Falle einer Many-to-One-Beziehung auf die der Kindobjekte innerhalb einer IN-Klausel, um verwandte Assoziationen zu laden.
>>> from sqlalchemy import select
>>> from sqlalchemy.orm import selectinload
>>> stmt = (
... select(User)
... .options(selectinload(User.addresses))
... .filter(or_(User.name == "spongebob", User.name == "ed"))
... )
>>> result = session.scalars(stmt).all()
SELECT
users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
WHERE users.name = ? OR users.name = ?
('spongebob', 'ed')
SELECT
addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id
FROM addresses
WHERE addresses.user_id IN (?, ?)
(5, 7)
Oben bezieht sich die zweite SELECT-Anweisung auf addresses.user_id IN (5, 7), wobei die "5" und "7" die Primärschlüsselwerte der beiden vorherigen geladenen User-Objekte sind; nachdem ein Stapel von Objekten vollständig geladen ist, werden ihre Primärschlüsselwerte in die IN-Klausel für die zweite SELECT-Anweisung eingefügt. Da die Beziehung zwischen User und Address eine einfache primäre Join-Bedingung hat und die Primärschlüsselwerte für User von Address.user_id abgeleitet werden können, enthält die Anweisung überhaupt keine Joins oder Unterabfragen.
Für einfache Many-to-One-Loads ist ebenfalls kein JOIN erforderlich, da der Fremdschlüsselwert des Elternobjekts verwendet wird.
>>> from sqlalchemy import select
>>> from sqlalchemy.orm import selectinload
>>> stmt = select(Address).options(selectinload(Address.user))
>>> result = session.scalars(stmt).all()
SELECT
addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id
FROM addresses
SELECT
users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
WHERE users.id IN (?, ?)
(1, 2)
Tipp
Mit "einfach" meinen wir, dass die relationship.primaryjoin-Bedingung einen Gleichheitsvergleich zwischen dem Primärschlüssel der "eins"-Seite und einem direkten Fremdschlüssel der "viele"-Seite ausdrückt, ohne zusätzliche Kriterien.
Select IN Loading unterstützt auch Many-to-Many-Beziehungen, bei denen es derzeit über alle drei Tabellen JOINt, um Zeilen von einer Seite zur anderen abzugleichen.
Zu diesem Ladeverfahren sind folgende Punkte zu beachten:
Die Strategie gibt eine SELECT-Anweisung für bis zu 500 Eltern-Primärschlüsselwerte gleichzeitig aus, da die Primärschlüssel in einen großen IN-Ausdruck in der SQL-Anweisung gerendert werden. Einige Datenbanken wie Oracle Database haben eine harte Grenze für die Größe eines IN-Ausdrucks, und insgesamt sollte die Größe des SQL-Strings nicht beliebig groß sein.
Da "selectin" Loading auf IN angewiesen ist, muss es bei einem Mapping mit zusammengesetzten Primärschlüsseln die "Tupel"-Form von IN verwenden, die wie folgt aussieht:
WHERE (table.column_a, table.column_b) IN ((?, ?), (?, ?), (?, ?)). Diese Syntax wird derzeit auf SQL Server nicht unterstützt und erfordert für SQLite mindestens Version 3.15. Es gibt keine spezielle Logik in SQLAlchemy, um im Voraus zu prüfen, welche Plattformen diese Syntax unterstützen oder nicht; wenn sie auf einer nicht unterstützenden Plattform ausgeführt wird, gibt die Datenbank sofort einen Fehler zurück. Ein Vorteil von SQLAlchemy, das SQL einfach auszuführen, damit es fehlschlägt, ist, dass es funktioniert, wenn eine bestimmte Datenbank diese Syntax zu unterstützen beginnt, ohne Änderungen an SQLAlchemy (wie es bei SQLite der Fall war).
Subquery Eager Loading¶
Legacy-Funktion
Der subqueryload() Eager Loader ist zu diesem Zeitpunkt meist veraltet und wurde durch die selectinload() Strategie ersetzt, die ein viel einfacheres Design hat, flexibler mit Funktionen wie Yield Per ist und in den meisten Fällen effizientere SQL-Anweisungen ausgibt. Da subqueryload() auf der Neuinterpretation der ursprünglichen SELECT-Anweisung beruht, kann es bei sehr komplexen Quellabfragen ineffizient funktionieren.
subqueryload() kann für den spezifischen Fall einer eager geladenen Sammlung für Objekte mit zusammengesetzten Primärschlüsseln auf dem Microsoft SQL Server-Backend, das weiterhin keine Unterstützung für die "Tupel IN"-Syntax hat, nützlich bleiben.
Subquery Loading ähnelt in seiner Funktionsweise dem Selectin Eager Loading, jedoch wird die ausgegebene SELECT-Anweisung aus der ursprünglichen Anweisung abgeleitet und hat eine komplexere Abfragestruktur als die von Selectin Eager Loading.
Subquery Eager Loading wird über das Argument "subquery" für relationship.lazy oder über die Loader-Option subqueryload() bereitgestellt.
Die Funktionsweise von Subquery Eager Loading besteht darin, für jede zu ladende Beziehung eine zweite SELECT-Anweisung auszugeben, die sich über alle Ergebnisobjekte erstreckt. Diese SELECT-Anweisung verweist auf die ursprüngliche SELECT-Anweisung, die in eine Unterabfrage eingeschlossen ist, so dass wir dieselbe Liste von Primärschlüsseln für das primäre zurückgegebene Objekt abrufen und diese dann mit der Summe aller Sammlungsmitglieder verknüpfen, um sie auf einmal zu laden.
>>> from sqlalchemy import select
>>> from sqlalchemy.orm import subqueryload
>>> stmt = select(User).options(subqueryload(User.addresses)).filter_by(name="spongebob")
>>> results = session.scalars(stmt).all()
SELECT
users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
WHERE users.name = ?
('spongebob',)
SELECT
addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id,
anon_1.users_id AS anon_1_users_id
FROM (
SELECT users.id AS users_id
FROM users
WHERE users.name = ?) AS anon_1
JOIN addresses ON anon_1.users_id = addresses.user_id
ORDER BY anon_1.users_id, addresses.id
('spongebob',)
Zu diesem Ladeverfahren sind folgende Punkte zu beachten:
Die von der "subquery"-Loader-Strategie ausgegebene SELECT-Anweisung erfordert im Gegensatz zu "selectin" eine Unterabfrage und übernimmt alle Leistungseinschränkungen, die in der ursprünglichen Abfrage vorhanden sind. Die Unterabfrage selbst kann auch Leistungseinbußen verursachen, abhängig von den Besonderheiten der verwendeten Datenbank.
"subquery" Loading erlegt einige spezielle Sortieranforderungen auf, um korrekt zu funktionieren. Eine Abfrage, die
subqueryload()in Verbindung mit einem limitierenden Modifikator wieSelect.limit()oderSelect.offset()verwendet, sollte **immer**Select.order_by()auf eindeutige Spalten (wie z. B. den Primärschlüssel) anwenden, damit die vonsubqueryload()ausgegebenen zusätzlichen Abfragen dieselbe Sortierung wie die übergeordnete Abfrage verwenden. Ohne diese besteht die Gefahr, dass die innere Abfrage die falschen Zeilen zurückgibt.# incorrect, no ORDER BY stmt = select(User).options(subqueryload(User.addresses).limit(1)) # incorrect if User.name is not unique stmt = select(User).options(subqueryload(User.addresses)).order_by(User.name).limit(1) # correct stmt = ( select(User) .options(subqueryload(User.addresses)) .order_by(User.name, User.id) .limit(1) )
Siehe auch
Warum wird ORDER BY bei LIMIT empfohlen (insbesondere bei subqueryload())? – Detailliertes Beispiel
"subquery" Loading verursacht zusätzliche Performance-/Komplexitätsprobleme, wenn es bei einem tief verschachtelten Eager Load verwendet wird, da Unterabfragen wiederholt verschachtelt werden.
"subquery" Loading ist nicht kompatibel mit dem "gebatched" Loading, das von Yield Per bereitgestellt wird, sowohl für Sammlungs- als auch für Skalarbeziehungen.
Aus den oben genannten Gründen sollte die "selectin"-Strategie gegenüber "subquery" bevorzugt werden.
Siehe auch
Welche Art von Loading soll verwendet werden?¶
Welcher Ladestyp verwendet werden soll, hängt in der Regel von der Optimierung des Kompromisses zwischen der Anzahl der SQL-Ausführungen, der Komplexität der ausgegebenen SQL und der Menge der abgerufenen Daten ab.
Eins zu Viele / Viele zu Viele Sammlung – Die selectinload() ist im Allgemeinen die beste Lade-Strategie. Sie gibt eine zusätzliche SELECT-Anweisung aus, die so wenige Tabellen wie möglich verwendet, wodurch die ursprüngliche Anweisung unberührt bleibt, und ist am flexibelsten für jede Art von Ursprungsabfrage. Ihre einzige wesentliche Einschränkung besteht bei der Verwendung einer Tabelle mit zusammengesetzten Primärschlüsseln auf einem Backend, das "Tupel IN" nicht unterstützt, was derzeit SQL Server und sehr alte SQLite-Versionen einschließt; alle anderen enthaltenen Backends unterstützen es.
Viele zu Eins – Die joinedload()-Strategie ist die universellste Strategie. In Sonderfällen kann auch die immediateload()-Strategie nützlich sein, wenn es nur sehr wenige potenzielle verwandte Werte gibt, da diese Strategie das Objekt aus der lokalen Session abruft, ohne SQL auszugeben, wenn das verwandte Objekt bereits vorhanden ist.
Polymorphe Eager Loading¶
Die Spezifikation von polymorphen Optionen auf Basis einer einzelnen Eager-Load ist unterstützt. Siehe den Abschnitt Eager Loading von polymorphen Untertypen für Beispiele der Methode PropComparator.of_type() in Verbindung mit der Funktion with_polymorphic().
Wildcard Loading Strategies¶
Jede der Optionen joinedload(), subqueryload(), lazyload(), selectinload() und raiseload() kann verwendet werden, um den Standardstil des relationship()-Ladens für eine bestimmte Abfrage festzulegen und alle relationship()-gemappten Attribute zu beeinflussen, die in der Anweisung nicht anderweitig spezifiziert sind. Diese Funktion ist verfügbar, indem der String '*' als Argument für eine dieser Optionen übergeben wird.
from sqlalchemy import select
from sqlalchemy.orm import lazyload
stmt = select(MyClass).options(lazyload("*"))Oben wird die Option lazyload('*') die Einstellung lazy aller verwendeten relationship()-Konstrukte für diese Abfrage überschreiben, mit Ausnahme derjenigen, die lazy='write_only' oder lazy='dynamic' verwenden.
Wenn einige Beziehungen beispielsweise lazy='joined' oder lazy='selectin' angeben, wird lazyload('*') diese Beziehungen einheitlich auf 'select'-Loading umstellen, d. h. eine SELECT-Anweisung ausgeben, wenn auf das Attribut zugegriffen wird.
Die Option überschreibt keine Loader-Optionen, die in der Abfrage angegeben sind, wie z. B. joinedload(), selectinload() usw. Die folgende Abfrage wird für die widget-Beziehung immer noch Joined Loading verwenden.
from sqlalchemy import select
from sqlalchemy.orm import lazyload
from sqlalchemy.orm import joinedload
stmt = select(MyClass).options(lazyload("*"), joinedload(MyClass.widget))Während die Anweisung für joinedload() oben unabhängig davon ausgeführt wird, ob sie vor oder nach der lazyload()-Option steht, gilt bei mehreren Optionen, die jeweils "*" enthielten, die letzte Option.
Entity-spezifische Wildcard-Lade-Strategien¶
Eine Variante der Wildcard-Loader-Strategie ist die Möglichkeit, die Strategie pro Entität festzulegen. Wenn wir beispielsweise nach User und Address abfragen, können wir alle Beziehungen zu Address auf Lazy Loading setzen, während die Loader-Strategien für User unverändert bleiben, indem wir zuerst das Load-Objekt anwenden und dann * als verkettete Option angeben.
from sqlalchemy import select
from sqlalchemy.orm import Load
stmt = select(User, Address).options(Load(Address).lazyload("*"))Oben werden alle Beziehungen zu Address auf Lazy Load gesetzt.
Routing von expliziten Joins/Anweisungen in eager geladene Sammlungen¶
Das Verhalten von joinedload() besteht darin, dass Joins automatisch erstellt werden, wobei anonyme Aliase als Ziele verwendet werden, deren Ergebnisse in Sammlungen und skalare Referenzen auf geladene Objekte geleitet werden. Es kommt oft vor, dass eine Abfrage bereits die notwendigen Joins enthält, die eine bestimmte Sammlung oder skalare Referenz darstellen, und die von der Joinedload-Funktion hinzugefügten Joins redundant sind – dennoch möchten Sie, dass die Sammlungen/Referenzen befüllt werden.
Hierfür stellt SQLAlchemy die Option contains_eager() bereit. Diese Option wird auf die gleiche Weise wie die Option joinedload() verwendet, nur dass davon ausgegangen wird, dass das Select-Objekt die entsprechenden Joins explizit enthält, typischerweise unter Verwendung von Methoden wie Select.join(). Im Folgenden spezifizieren wir einen Join zwischen User und Address und legen zusätzlich fest, dass dies die Grundlage für das Eager Loading von User.addresses ist.
from sqlalchemy.orm import contains_eager
stmt = select(User).join(User.addresses).options(contains_eager(User.addresses))Wenn der "eager"-Teil der Anweisung "aliased" ist, sollte der Pfad über PropComparator.of_type() angegeben werden, wodurch das spezifische aliased()-Konstrukt übergeben werden kann.
# use an alias of the Address entity
adalias = aliased(Address)
# construct a statement which expects the "addresses" results
stmt = (
select(User)
.outerjoin(User.addresses.of_type(adalias))
.options(contains_eager(User.addresses.of_type(adalias)))
)
# get results normally
r = session.scalars(stmt).unique().all()
SELECT
users.user_id AS users_user_id,
users.user_name AS users_user_name,
adalias.address_id AS adalias_address_id,
adalias.user_id AS adalias_user_id,
adalias.email_address AS adalias_email_address,
(...other columns...)
FROM users
LEFT OUTER JOIN email_addresses AS email_addresses_1
ON users.user_id = email_addresses_1.user_id
Der Pfad, der als Argument für contains_eager() angegeben wird, muss ein vollständiger Pfad von der Ausgangsentität sein. Wenn wir beispielsweise Users->orders->Order->items->Item laden würden, würde die Option wie folgt verwendet:
stmt = select(User).options(contains_eager(User.orders).contains_eager(Order.items))Verwendung von contains_eager() zum Laden eines Sammlungsergebnisses mit benutzerdefinierter Filterung¶
Wenn wir contains_eager() verwenden, erstellen *wir* die SQL, die zum Befüllen von Sammlungen verwendet wird. Daraus ergibt sich natürlich, dass wir wählen können, welche Werte die Sammlung speichern soll, indem wir unsere SQL so schreiben, dass eine Teilmenge von Elementen für Sammlungen oder skalare Attribute geladen wird.
Tipp
SQLAlchemy bietet nun eine **wesentlich einfachere Möglichkeit**, indem es erlaubt, WHERE-Kriterien direkt zu Ladeoptionen wie joinedload() und selectinload() über PropComparator.and_() hinzuzufügen. Siehe den Abschnitt Hinzufügen von Kriterien zu Ladeoptionen für Beispiele.
Die hier beschriebenen Techniken gelten weiterhin, wenn die zugehörige Sammlung über SQL-Kriterien oder Modifikatoren abgefragt werden soll, die komplexer als eine einfache WHERE-Klausel sind.
Als Beispiel können wir ein User-Objekt laden und nur bestimmte Adressen in seine .addresses-Sammlung eager laden, indem wir die verknüpften Daten filtern, sie über contains_eager() leiten, und auch Populate Existing verwenden, um sicherzustellen, dass bereits geladene Sammlungen überschrieben werden.
stmt = (
select(User)
.join(User.addresses)
.filter(Address.email_address.like("%@aol.com"))
.options(contains_eager(User.addresses))
.execution_options(populate_existing=True)
)Die obige Abfrage lädt nur User-Objekte, die mindestens ein Address-Objekt enthalten, das den Unterstring 'aol.com' im Feld email hat; die User.addresses-Sammlung wird **nur** diese Address-Einträge enthalten und *nicht* andere Address-Einträge, die tatsächlich mit der Sammlung verbunden sind.
Tipp
In allen Fällen überschreibt die SQLAlchemy ORM **bereits geladene Attribute und Sammlungen nicht**, es sei denn, sie wird dazu aufgefordert. Da eine Identitätskarte verwendet wird, kommt es oft vor, dass eine ORM-Abfrage Objekte zurückgibt, die tatsächlich bereits im Speicher vorhanden und geladen waren. Daher ist es bei der Verwendung von contains_eager() zum Befüllen einer Sammlung auf alternative Weise in der Regel eine gute Idee, Populate Existing zu verwenden, wie oben gezeigt, damit eine bereits geladene Sammlung mit den neuen Daten aktualisiert wird. Die Option populate_existing setzt **alle** bereits vorhandenen Attribute zurück, einschließlich ausstehender Änderungen. Stellen Sie daher sicher, dass alle Daten vor der Verwendung geflusht werden. Die Verwendung der Session mit ihrem Standardverhalten autoflush ist ausreichend.
Hinweis
Die mit contains_eager() geladene benutzerdefinierte Sammlung ist nicht "sticky", d. h. beim nächsten Laden dieser Sammlung wird sie mit ihrem üblichen Standardinhalt geladen. Die Sammlung unterliegt der Neuladung, wenn das Objekt abgelaufen ist, was jedes Mal geschieht, wenn die Methoden Session.commit() oder Session.rollback() verwendet werden (bei Standard-Sitzungseinstellungen) oder die Methoden Session.expire_all() oder Session.expire() verwendet werden.
Siehe auch
Hinzufügen von Kriterien zu Ladeoptionen – moderne API, die WHERE-Kriterien direkt innerhalb jeder Ladeoption für Beziehungen ermöglicht.
Beziehungs-Loader-API¶
| Objektname | Beschreibung |
|---|---|
contains_eager(*keys, **kw) |
Gibt an, dass das angegebene Attribut aus explizit in der Abfrage definierten Spalten eager geladen werden soll. |
defaultload(*keys) |
Gibt an, dass ein Attribut mit seinem vordefinierten Laderstil geladen werden soll. |
immediateload(*keys, [recursion_depth]) |
Gibt an, dass das angegebene Attribut mit einem sofortigen Ladevorgang über eine pro Attribut ausgegebene SELECT-Anweisung geladen werden soll. |
joinedload(*keys, **kw) |
Gibt an, dass das angegebene Attribut mittels Joined Eager Loading geladen werden soll. |
lazyload(*keys) |
Gibt an, dass das angegebene Attribut mittels "lazy" Loading geladen werden soll. |
Repräsentiert Ladeoptionen, die den Zustand eines ORM-fähigen |
|
noload(*keys) |
Gibt an, dass das angegebene Beziehungsattribut ungeladen bleiben soll. |
raiseload(*keys, **kw) |
Gibt an, dass beim Zugriff auf das angegebene Attribut ein Fehler ausgelöst werden soll. |
selectinload(*keys, [recursion_depth]) |
Gibt an, dass das angegebene Attribut mittels SELECT IN Eager Loading geladen werden soll. |
subqueryload(*keys) |
Gibt an, dass das angegebene Attribut mittels Subquery Eager Loading geladen werden soll. |
- funktion sqlalchemy.orm.contains_eager(*keys: Literal['*'] | QueryableAttribute[Any], **kw: Any) → _AbstractLoad¶
Gibt an, dass das angegebene Attribut aus explizit in der Abfrage definierten Spalten eager geladen werden soll.
Diese Funktion ist Teil der
LoadSchnittstelle und unterstützt sowohl verkettete als auch eigenständige Operationen.Die Option wird in Verbindung mit einem expliziten Join verwendet, der die gewünschten Zeilen lädt, d.h.
sess.query(Order).join(Order.user).options(contains_eager(Order.user))
Die obige Abfrage würde von der
OrderEntität zu ihrer zugehörigenUserEntität joinen, und die zurückgegebenenOrderObjekte hätten dasOrder.userAttribut vorab geladen.Sie kann auch zur Anpassung der Einträge in einer eager geladenen Kollektion verwendet werden; Abfragen werden normalerweise die Populate Existing Ausführungsoption verwenden, vorausgesetzt, die primäre Kollektion von übergeordneten Objekten wurde möglicherweise bereits geladen
sess.query(User).join(User.addresses).filter( Address.email_address.like("%@aol.com") ).options(contains_eager(User.addresses)).populate_existing()
Siehe den Abschnitt Routing von expliziten Joins/Statements in eager geladene Kollektionen für vollständige Nutzungsdetails.
- funktion sqlalchemy.orm.defaultload(*keys: Literal['*'] | QueryableAttribute[Any]) → _AbstractLoad¶
Gibt an, dass ein Attribut mit seinem vordefinierten Laderstil geladen werden soll.
Das Verhalten dieser Ladeoption ist, den aktuellen Ladestil des Attributs nicht zu ändern, was bedeutet, dass der zuvor konfigurierte verwendet wird oder, falls kein vorheriger Stil ausgewählt wurde, das Standardladen verwendet wird.
Diese Methode wird verwendet, um zu anderen Ladeoptionen in einer Kette von Attributen zu verlinken, ohne den Ladestil der Links entlang der Kette zu ändern. Zum Beispiel, um ein joined eager Loading für ein Element eines Elements einzustellen
session.query(MyClass).options( defaultload(MyClass.someattribute).joinedload( MyOtherClass.someotherattribute ) )
defaultload()ist auch nützlich, um spaltenbezogene Optionen für eine verwandte Klasse festzulegen, nämlichdefer()undundefer()session.scalars( select(MyClass).options( defaultload(MyClass.someattribute) .defer("some_column") .undefer("some_other_column") ) )
- funktion sqlalchemy.orm.immediateload(*keys: Literal['*'] | QueryableAttribute[Any], recursion_depth: int | None = None) → _AbstractLoad¶
Gibt an, dass das angegebene Attribut mit einem sofortigen Ladevorgang über eine pro Attribut ausgegebene SELECT-Anweisung geladen werden soll.
Das Laden wird mit der "lazyloader"-Strategie erreicht und löst keine zusätzlichen eager loader aus.
Die Option
immediateload()wird im Allgemeinen von derselectinload()Option abgelöst, die die gleiche Aufgabe effizienter erfüllt, indem sie ein SELECT für alle geladenen Objekte ausgibt.Diese Funktion ist Teil der
LoadSchnittstelle und unterstützt sowohl verkettete als auch eigenständige Operationen.- Parameter:
recursion_depth¶ –
optional int; wenn auf eine positive Ganzzahl in Verbindung mit einer selbstreferenziellen Beziehung gesetzt, gibt dies an, dass das "selectin"-Laden automatisch so viele Ebenen tief fortgesetzt wird, bis keine Elemente mehr gefunden werden.
Hinweis
Die Option
immediateload.recursion_depthunterstützt derzeit nur selbstreferenzielle Beziehungen. Es gibt noch keine Option, rekursive Strukturen mit mehr als einer beteiligten Beziehung automatisch zu durchlaufen.Warnung
Dieser Parameter ist neu und experimentell und sollte als "Alpha"-Status betrachtet werden
Neu in Version 2.0: hinzugefügt
immediateload.recursion_depth
- funktion sqlalchemy.orm.joinedload(*keys: Literal['*'] | QueryableAttribute[Any], **kw: Any) → _AbstractLoad¶
Gibt an, dass das angegebene Attribut mittels Joined Eager Loading geladen werden soll.
Diese Funktion ist Teil der
LoadSchnittstelle und unterstützt sowohl verkettete als auch eigenständige Operationen.examples
# joined-load the "orders" collection on "User" select(User).options(joinedload(User.orders)) # joined-load Order.items and then Item.keywords select(Order).options(joinedload(Order.items).joinedload(Item.keywords)) # lazily load Order.items, but when Items are loaded, # joined-load the keywords collection select(Order).options(lazyload(Order.items).joinedload(Item.keywords))
- Parameter:
innerjoin¶ –
wenn
True, gibt an, dass der joined eager load einen inner join anstelle des standardmäßigen left outer join verwenden sollselect(Order).options(joinedload(Order.user, innerjoin=True))
Um mehrere eager Joins zu verketten, bei denen einige OUTER und andere INNER sein können, werden rechtsverschachtelte Joins verwendet, um sie zu verknüpfen
select(A).options( joinedload(A.bs, innerjoin=False).joinedload(B.cs, innerjoin=True) )
Die obige Abfrage, die A.bs über einen "outer" Join und B.cs über einen "inner" Join verknüpft, würde die Joins als "a LEFT OUTER JOIN (b JOIN c)" rendern. Bei Verwendung älterer SQLite-Versionen (< 3.7.16) wird diese Form von JOIN in vollständige Subqueries übersetzt, da diese Syntax ansonsten nicht direkt unterstützt wird.
Das Flag
innerjoinkann auch mit dem Begriff"unnested"angegeben werden. Dies bedeutet, dass ein INNER JOIN verwendet werden soll, es sei denn, der Join ist mit einem LEFT OUTER JOIN links verbunden, in diesem Fall wird er als LEFT OUTER JOIN gerendert. Zum Beispiel, angenommen,A.bsist ein outerjoinselect(A).options(joinedload(A.bs).joinedload(B.cs, innerjoin="unnested"))
Der obige Join wird als "a LEFT OUTER JOIN b LEFT OUTER JOIN c" gerendert und nicht als "a LEFT OUTER JOIN (b JOIN c)".
Hinweis
Das Flag "unnested" wirkt sich **nicht** auf den JOIN aus, der von einer Many-to-Many-Assoziationstabelle erzeugt wird, z. B. einer Tabelle, die als
relationship.secondaryzur Zielspalte konfiguriert ist; zur Korrektheit der Ergebnisse sind diese Joins immer INNER und werden daher rechtsverschachtelt, wenn sie mit einem OUTER Join verbunden sind.Hinweis
Die von
joinedload()erzeugten Joins sind **anonym mit Alias versehen**. Die Kriterien, nach denen der Join erfolgt, können nicht geändert werden, noch können die ORM-aktiviertenSelectoder LegacyQueryauf diese Joins verweisen, einschließlich der Sortierung. Siehe Der Zen des Joined Eager Loading für weitere Details.Um einen spezifischen SQL JOIN zu erzeugen, der explizit verfügbar ist, verwenden Sie
Select.join()undQuery.join(). Um explizite JOINs mit eager Loading von Kollektionen zu kombinieren, verwenden Siecontains_eager(); siehe Routing von expliziten Joins/Statements in eager geladene Kollektionen.
- funktion sqlalchemy.orm.lazyload(*keys: Literal['*'] | QueryableAttribute[Any]) → _AbstractLoad¶
Gibt an, dass das angegebene Attribut mittels "lazy" Loading geladen werden soll.
Diese Funktion ist Teil der
LoadSchnittstelle und unterstützt sowohl verkettete als auch eigenständige Operationen.
- klasse sqlalchemy.orm.Load¶
Repräsentiert Ladeoptionen, die den Zustand eines ORM-fähigen
Selectoder einer älterenQuerymodifizieren, um zu beeinflussen, wie verschiedene gemappte Attribute geladen werden.Das
LoadObjekt wird in den meisten Fällen im Hintergrund verwendet, wenn man eine Abfrageoption wiejoinedload(),defer()oder ähnliches verwendet. Es wird normalerweise nicht direkt instanziiert, außer in sehr spezifischen Fällen.Siehe auch
Per-Entität-Wildcard-Ladestrategien - illustriert ein Beispiel, wo die direkte Verwendung von
Loadnützlich sein kannMitglieder
contains_eager(), defaultload(), defer(), get_children(), immediateload(), inherit_cache, joinedload(), lazyload(), load_only(), noload(), options(), process_compile_state(), process_compile_state_replaced_entities(), propagate_to_loaders, raiseload(), selectin_polymorphic(), selectinload(), subqueryload(), undefer(), undefer_group(), with_expression()
Klassensignatur
klasse
sqlalchemy.orm.Load(sqlalchemy.orm.strategy_options._AbstractLoad)-
methode
sqlalchemy.orm.Load.contains_eager(attr: _AttrType, alias: _FromClauseArgument | None = None, _is_chain: bool = False, _propagate_to_loaders: bool = False) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.contains_eagerMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
LoadObjekt mit der angewendetencontains_eager()Option.Siehe
contains_eager()für Anwendungsbeispiele.
-
methode
sqlalchemy.orm.Load.defaultload(attr: Literal['*'] | QueryableAttribute[Any]) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.defaultloadMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
LoadObjekt mit der angewendetendefaultload()Option.Siehe
defaultload()für Anwendungsbeispiele.
-
methode
sqlalchemy.orm.Load.defer(key: Literal['*'] | QueryableAttribute[Any], raiseload: bool = False) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.deferMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
LoadObjekt mit der angewendetendefer()Option.Siehe
defer()für Anwendungsbeispiele.
-
methode
sqlalchemy.orm.Load.get_children(*, omit_attrs: Tuple[str, ...] = (), **kw: Any) → Iterable[HasTraverseInternals]¶ geerbt von der
HasTraverseInternals.get_children()Methode vonHasTraverseInternalsGibt direkte Kind-Elemente
HasTraverseInternalsdiesesHasTraverseInternalszurück.Dies wird für die Besuchs-Traversal verwendet.
**kw kann Flags enthalten, die die zurückgegebene Sammlung ändern, z. B. um eine Teilmenge von Elementen zurückzugeben, um größere Traversierungen zu reduzieren, oder um Kind-Elemente aus einem anderen Kontext zurückzugeben (z. B. Schema-Ebene Sammlungen anstelle von Klausel-Ebene).
-
methode
sqlalchemy.orm.Load.immediateload(attr: Literal['*'] | QueryableAttribute[Any], recursion_depth: int | None = None) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.immediateloadMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
LoadObjekt mit der angewendetenimmediateload()Option.Siehe
immediateload()für Anwendungsbeispiele.
-
attribut
sqlalchemy.orm.Load.inherit_cache: bool | None = None¶ geerbt von der
HasCacheKey.inherit_cacheAttribut vonHasCacheKeyGibt an, ob diese
HasCacheKeyInstanz das Cache-Schlüssel-Generierungsschema ihrer direkten Oberklasse verwenden soll.Das Attribut hat standardmäßig den Wert
None, was bedeutet, dass ein Konstrukt noch nicht berücksichtigt hat, ob es für die Teilnahme an der Caching-Mechanik geeignet ist. Dies ist funktional äquivalent zum Setzen des Wertes aufFalse, außer dass auch eine Warnung ausgegeben wird.Dieses Flag kann auf
Truefür eine bestimmte Klasse gesetzt werden, wenn die SQL, die diesem Objekt entspricht, nicht auf Basis von Attributen geändert wird, die lokal zu dieser Klasse und nicht zu ihrer Oberklasse gehören.Siehe auch
Caching-Unterstützung für benutzerdefinierte Konstrukte aktivieren - Allgemeine Richtlinien für die Einstellung des
HasCacheKey.inherit_cacheAttributs für benutzerdefinierte oder von Drittanbietern erstellte SQL-Konstrukte.
-
methode
sqlalchemy.orm.Load.joinedload(attr: Literal['*'] | QueryableAttribute[Any], innerjoin: bool | None = None) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.joinedloadMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
LoadObjekt mit der angewendetenjoinedload()Option.Siehe
joinedload()für Anwendungsbeispiele.
-
methode
sqlalchemy.orm.Load.lazyload(attr: Literal['*'] | QueryableAttribute[Any]) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.lazyloadMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
LoadObjekt mit der angewendetenlazyload()Option.Siehe
lazyload()für Anwendungsbeispiele.
-
methode
sqlalchemy.orm.Load.load_only(*attrs: Literal['*'] | QueryableAttribute[Any], raiseload: bool = False) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.load_onlyMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
LoadObjekt mit der angewendetenload_only()Option.Siehe
load_only()für Anwendungsbeispiele.
-
Methode
sqlalchemy.orm.Load.noload(attr: Literal['*'] | QueryableAttribute[Any]) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.noloadMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
Load-Objekt mit der angewendetennoload()-Option.Siehe
noload()für Anwendungsbeispiele.
-
Methode
sqlalchemy.orm.Load.options(*opts: _AbstractLoad) → Self¶ Wendet eine Reihe von Optionen als Unteroptionen auf dieses
Load-Objekt an.Z. B.
query = session.query(Author) query = query.options( joinedload(Author.book).options( load_only(Book.summary, Book.excerpt), joinedload(Book.citations).options(joinedload(Citation.author)), ) )
- Parameter:
*opts¶ – Eine Reihe von Loader-Options-Objekten (letztendlich
Load-Objekte), die auf den von diesemLoad-Objekt angegebenen Pfad angewendet werden sollen.
Neu in Version 1.3.6.
-
Methode
sqlalchemy.orm.Load.process_compile_state(compile_state: ORMCompileState) → None¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.process_compile_stateMethode vonsqlalchemy.orm.strategy_options._AbstractLoadModifiziert einen gegebenen
ORMCompileState.Diese Methode ist Teil der Implementierung einer bestimmten
CompileStateOptionund wird nur intern aufgerufen, wenn eine ORM-Abfrage kompiliert wird.
-
Methode
sqlalchemy.orm.Load.process_compile_state_replaced_entities(compile_state: ORMCompileState, mapper_entities: Sequence[_MapperEntity]) → None¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.process_compile_state_replaced_entitiesMethode vonsqlalchemy.orm.strategy_options._AbstractLoadModifiziert einen gegebenen
ORMCompileStateunter Berücksichtigung von Entitäten, die durch with_only_columns() oder with_entities() ersetzt wurden.Diese Methode ist Teil der Implementierung einer bestimmten
CompileStateOptionund wird nur intern aufgerufen, wenn eine ORM-Abfrage kompiliert wird.Neu in Version 1.4.19.
-
Attribut
sqlalchemy.orm.Load.propagate_to_loaders: bool¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.propagate_to_loadersAttribut vonsqlalchemy.orm.strategy_options._AbstractLoadWenn True, wird angegeben, dass diese Option auch für "sekundäre" SELECT-Anweisungen, die für Relationship Lazy Loader auftreten, sowie für Attributlade- / Aktualisierungsoperationen übernommen werden soll.
-
Methode
sqlalchemy.orm.Load.raiseload(attr: Literal['*'] | QueryableAttribute[Any], sql_only: bool = False) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.raiseloadMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
Load-Objekt mit der angewendetenraiseload()-Option.Siehe
raiseload()für Anwendungsbeispiele.
-
Methode
sqlalchemy.orm.Load.selectin_polymorphic(classes: Iterable[Type[Any]]) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.selectin_polymorphicMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
Load-Objekt mit der angewendetenselectin_polymorphic()-Option.Siehe
selectin_polymorphic()für Anwendungsbeispiele.
-
Methode
sqlalchemy.orm.Load.selectinload(attr: Literal['*'] | QueryableAttribute[Any], recursion_depth: int | None = None) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.selectinloadMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
Load-Objekt mit der angewendetenselectinload()-Option.Siehe
selectinload()für Anwendungsbeispiele.
-
Methode
sqlalchemy.orm.Load.subqueryload(attr: Literal['*'] | QueryableAttribute[Any]) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.subqueryloadMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
Load-Objekt mit der angewendetensubqueryload()-Option.Siehe
subqueryload()für Anwendungsbeispiele.
-
Methode
sqlalchemy.orm.Load.undefer(key: Literal['*'] | QueryableAttribute[Any]) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.undeferMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
Load-Objekt mit der angewendetenundefer()-Option.Siehe
undefer()für Anwendungsbeispiele.
-
Methode
sqlalchemy.orm.Load.undefer_group(name: str) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.undefer_groupMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
Load-Objekt mit der angewendetenundefer_group()-Option.Siehe
undefer_group()für Anwendungsbeispiele.
-
Methode
sqlalchemy.orm.Load.with_expression(key: _AttrType, expression: _ColumnExpressionArgument[Any]) → Self¶ geerbt von der
sqlalchemy.orm.strategy_options._AbstractLoad.with_expressionMethode vonsqlalchemy.orm.strategy_options._AbstractLoadErzeugt ein neues
Load-Objekt mit der angewendetenwith_expression()-Option.Siehe
with_expression()für Anwendungsbeispiele.
-
methode
- Funktion sqlalchemy.orm.noload(*keys: Literal['*'] | QueryableAttribute[Any]) → _AbstractLoad¶
Gibt an, dass das angegebene Beziehungsattribut ungeladen bleiben soll.
Das Relationship-Attribut gibt
Nonezurück, wenn es ohne Ladeeffekt zugegriffen wird.Diese Funktion ist Teil der
LoadSchnittstelle und unterstützt sowohl verkettete als auch eigenständige Operationen.noload()gilt nur fürrelationship()-Attribute.Legacy-Funktion
Die
noload()-Option ist **veraltet**. Sie zwingt Sammlungen dazu, leer zu sein, was unweigerlich zu unintuitiven und schwer vorhersehbaren Ergebnissen führt. Es gibt keine legitimen Anwendungsfälle für diese Option im modernen SQLAlchemy.Siehe auch
- Funktion sqlalchemy.orm.raiseload(*keys: Literal['*'] | QueryableAttribute[Any], **kw: Any) → _AbstractLoad¶
Gibt an, dass beim Zugriff auf das angegebene Attribut ein Fehler ausgelöst werden soll.
Ein mit
raiseload()konfiguriertes Relationship-Attribut löst bei Zugriff eineInvalidRequestErroraus. Der typische Nutzen liegt darin, wenn eine Anwendung sicherstellen möchte, dass alle Relationship-Attribute, auf die in einem bestimmten Kontext zugegriffen wird, bereits per Eager Loading geladen wurden. Anstatt die SQL-Logs zu durchsuchen, um sicherzustellen, dass keine Lazy Loads auftreten, löst diese Strategie diese sofort aus.raiseload()gilt nur fürrelationship()-Attribute. Um das Raise-on-SQL-Verhalten auf ein spaltenbasiertes Attribut anzuwenden, verwenden Sie den Parameterdefer.raiseloadin der Loader-Optiondefer().- Parameter:
sql_only¶ – wenn True, wird nur dann ausgelöst, wenn der Lazy Load SQL emittieren würde, aber nicht, wenn nur die Identity Map geprüft wird oder festgestellt wird, dass der zugehörige Wert aufgrund fehlender Schlüssel einfach None sein soll. Wenn False, löst die Strategie bei allen Arten von Relationship-Ladevorgängen aus.
Diese Funktion ist Teil der
LoadSchnittstelle und unterstützt sowohl verkettete als auch eigenständige Operationen.
- Funktion sqlalchemy.orm.selectinload(*keys: Literal['*'] | QueryableAttribute[Any], recursion_depth: int | None = None) → _AbstractLoad¶
Gibt an, dass das angegebene Attribut mittels SELECT IN Eager Loading geladen werden soll.
Diese Funktion ist Teil der
LoadSchnittstelle und unterstützt sowohl verkettete als auch eigenständige Operationen.examples
# selectin-load the "orders" collection on "User" select(User).options(selectinload(User.orders)) # selectin-load Order.items and then Item.keywords select(Order).options( selectinload(Order.items).selectinload(Item.keywords) ) # lazily load Order.items, but when Items are loaded, # selectin-load the keywords collection select(Order).options(lazyload(Order.items).selectinload(Item.keywords))
- Parameter:
recursion_depth¶ –
optional int; wenn auf eine positive Ganzzahl in Verbindung mit einer selbstreferenziellen Beziehung gesetzt, gibt dies an, dass das "selectin"-Laden automatisch so viele Ebenen tief fortgesetzt wird, bis keine Elemente mehr gefunden werden.
Hinweis
Die Option
selectinload.recursion_depthunterstützt derzeit nur selbstreferenzielle Beziehungen. Es gibt noch keine Option, rekursive Strukturen mit mehr als einer beteiligten Beziehung automatisch zu durchlaufen.Zusätzlich ist der Parameter
selectinload.recursion_depthneu und experimentell und sollte für die 2.0-Serie als "Alpha"-Status behandelt werden.Neu in Version 2.0:
selectinload.recursion_depthhinzugefügt
- Funktion sqlalchemy.orm.subqueryload(*keys: Literal['*'] | QueryableAttribute[Any]) → _AbstractLoad¶
Gibt an, dass das angegebene Attribut mittels Subquery Eager Loading geladen werden soll.
Diese Funktion ist Teil der
LoadSchnittstelle und unterstützt sowohl verkettete als auch eigenständige Operationen.examples
# subquery-load the "orders" collection on "User" select(User).options(subqueryload(User.orders)) # subquery-load Order.items and then Item.keywords select(Order).options( subqueryload(Order.items).subqueryload(Item.keywords) ) # lazily load Order.items, but when Items are loaded, # subquery-load the keywords collection select(Order).options(lazyload(Order.items).subqueryload(Item.keywords))
Die Designs von flambé! dem Drachen und Der Alchemist wurden von Rotem Yaari erstellt und großzügig gespendet.
Erstellt mit Sphinx 7.2.6. Dokumentation zuletzt generiert: Di 11 Mär 2025 14:40:17 EDT