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
- Techniken für das Laden von Beziehungen
- ORM API Features für Abfragen¶
- Legacy Query API
- Verwendung der Sitzung
- Ereignisse und Interna
- ORM Erweiterungen
- ORM Beispiele
Projektversionen
- Vorhergehend: Relationship Loading Techniques
- Nächste: Legacy Query API
- Oben: Startseite
- Auf dieser Seite
ORM API Features für Abfragen¶
ORM Ladeoptionen¶
Ladeoptionen sind Objekte, die, wenn sie an die Methode Select.options() eines Select-Objekts oder ähnliche SQL-Konstrukte übergeben werden, das Laden von spalten- und beziehungsbezogenen Attributen beeinflussen. Die meisten Ladeoptionen erben von der Load-Hierarchie. Eine vollständige Übersicht über die Verwendung von Ladeoptionen finden Sie in den unten verlinkten Abschnitten.
Siehe auch
Spaltenladeoptionen - Details zu Mapper- und Ladeoptionen, die beeinflussen, wie spalten- und SQL-ausdrucksbezogene zugeordnete Attribute geladen werden
Relationship Loading Techniques - Details zu Beziehungs- und Ladeoptionen, die beeinflussen, wie
relationship()zugeordnete Attribute geladen werden
ORM Ausführungsoptionen¶
Ausführungsoptionen auf ORM-Ebene sind Schlüsselwortoptionen, die mit einer Anweisungsausführung verknüpft werden können, entweder über den Parameter Session.execute.execution_options, der ein Dictionary-Argument ist, das von Session-Methoden wie Session.execute() und Session.scalars() akzeptiert wird, oder indem sie direkt der auszuführenden Anweisung über die Methode Executable.execution_options() zugeordnet werden, die sie als beliebige Schlüsselwortargumente akzeptiert.
Optionen auf ORM-Ebene unterscheiden sich von den Ausführungsoptionen auf Core-Ebene, die unter Connection.execution_options() dokumentiert sind. Es ist wichtig zu beachten, dass die unten diskutierten ORM-Optionen **nicht** mit den Core-Level-Methoden Connection.execution_options() oder Engine.execution_options() kompatibel sind; die Optionen werden auf dieser Ebene ignoriert, selbst wenn die Engine oder Connection mit der verwendeten Session verknüpft ist.
In diesem Abschnitt wird der Stil der Methode Executable.execution_options() für Beispiele verwendet.
Bestehendes auffüllen¶
Die Ausführungsoption populate_existing stellt sicher, dass für alle geladenen Zeilen die entsprechenden Instanzen in der Session vollständig aktualisiert werden – alle vorhandenen Daten in den Objekten (einschließlich ausstehender Änderungen) werden gelöscht und durch die aus dem Ergebnis geladenen Daten ersetzt.
Die beispielhafte Verwendung sieht so aus
>>> stmt = select(User).execution_options(populate_existing=True)
>>> result = session.execute(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
...
Normalerweise werden ORM-Objekte nur einmal geladen, und wenn sie in einer nachfolgenden Ergebniszeile mit dem Primärschlüssel übereinstimmen, wird die Zeile nicht auf das Objekt angewendet. Dies dient sowohl dem Schutz ausstehender, noch nicht gefluschter Änderungen am Objekt als auch der Vermeidung des Overheads und der Komplexität der Aktualisierung bereits vorhandener Daten. Die Session geht von einem Standardarbeitsmodell einer hochisolierten Transaktion aus, und in dem Maße, in dem Daten innerhalb der Transaktion außerhalb der lokalen Änderungen von Änderungen betroffen sind, würden diese Anwendungsfälle mit expliziten Schritten wie dieser Methode behandelt.
Mit populate_existing kann jede Gruppe von Objekten, die mit einer Abfrage übereinstimmen, aktualisiert werden, und es ermöglicht auch die Steuerung von Beziehungs-Ladeoptionen. Z.B. um eine Instanz zu aktualisieren und gleichzeitig eine zugehörige Gruppe von Objekten zu aktualisieren
stmt = (
select(User)
.where(User.name.in_(names))
.execution_options(populate_existing=True)
.options(selectinload(User.addresses))
)
# will refresh all matching User objects as well as the related
# Address objects
users = session.execute(stmt).scalars().all()Ein weiterer Anwendungsfall für populate_existing ist die Unterstützung verschiedener Attributladefunktionen, die beeinflussen können, wie ein Attribut pro Abfrage geladen wird. Optionen, für die dies gilt, sind
Die Option
with_expression()Die Methode
PropComparator.and_(), die modifizieren kann, was eine Ladestrategie lädtDie Option
contains_eager()Die Option
with_loader_criteria()Die Option
load_only()zur Auswahl der zu aktualisierenden Attribute
Die Ausführungsoption populate_existing ist äquivalent zur Methode Query.populate_existing() in ORM-Abfragen im 1.x-Stil.
Siehe auch
Ich lade Daten mit meiner Session neu, aber sie sieht keine Änderungen, die ich anderswo committet habe - in Häufig gestellte Fragen
Aktualisieren / Verwerfen - in der ORM-Dokumentation Session
Autoflush¶
Diese Option wird, wenn sie als False übergeben wird, dazu führen, dass die Session den "autoflush"-Schritt nicht ausführt. Sie ist äquivalent zur Verwendung des Kontextmanagers Session.no_autoflush, um autoflush zu deaktivieren.
>>> stmt = select(User).execution_options(autoflush=False)
>>> session.execute(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
...
Diese Option funktioniert auch bei ORM-aktivierten Update- und Delete-Abfragen.
Die Ausführungsoption autoflush ist äquivalent zur Methode Query.autoflush() in ORM-Abfragen im 1.x-Stil.
Siehe auch
Abrufen großer Ergebnissets mit Yield Per¶
Die Ausführungsoption yield_per ist ein Integerwert, der dazu führt, dass das Result nur eine begrenzte Anzahl von Zeilen und/oder ORM-Objekten auf einmal puffert, bevor Daten für den Client verfügbar gemacht werden.
Normalerweise ruft die ORM **alle** Zeilen sofort ab, erstellt für jede ORM-Objekte und fasst diese Objekte in einem einzigen Puffer zusammen, bevor dieser Puffer dem Result-Objekt als Quelle für zurückzugebende Zeilen übergeben wird. Die Begründung für dieses Verhalten ist, korrekte Ergebnisse für Funktionen wie Joined Eager Loading, Entitäten-Unifizierung und die allgemeine Verarbeitung von Ergebnissen zu ermöglichen, die auf der Identitätszuordnung basieren, um einen konsistenten Zustand für jedes Objekt in einem Ergebnisset zu gewährleisten, während es abgerufen wird.
Der Zweck der Option yield_per ist es, dieses Verhalten zu ändern, sodass das ORM-Ergebnisset für die Iteration durch sehr große Ergebnissets (z. B. > 10.000 Zeilen) optimiert ist, bei denen der Benutzer festgestellt hat, dass die oben genannten Muster nicht zutreffen. Wenn yield_per verwendet wird, werden die ORM-Ergebnisse in Teil-Kollektionen gebatcht und Zeilen aus jeder Teil-Kollektion einzeln geliefert, während das Result-Objekt iteriert wird, sodass der Python-Interpreter keine sehr großen Speicherbereiche deklarieren muss, was sowohl zeitaufwendig ist als auch zu übermäßiger Speichernutzung führt. Die Option beeinflusst sowohl die Art und Weise, wie der Datenbankcursor verwendet wird, als auch wie die ORM Zeilen und Objekte erstellt, die an das Result übergeben werden.
Tipp
Aus dem Obigen ergibt sich, dass das Result iterativ verarbeitet werden muss, d. h. durch Iteration wie for row in result oder durch die Verwendung von partiellen Zeilenmethoden wie Result.fetchmany() oder Result.partitions(). Das Aufrufen von Result.all() untergräbt den Zweck der Verwendung von yield_per.
Die Verwendung von yield_per ist äquivalent zur Verwendung der Ausführungsoption Connection.execution_options.stream_results, die serverseitige Cursors für das Backend auswählt, falls unterstützt, und der Methode Result.yield_per() des zurückgegebenen Result-Objekts, die eine feste Anzahl von Zeilen festlegt, die abgerufen werden sollen, sowie eine entsprechende Begrenzung für die Anzahl der gleichzeitig zu erstellenden ORM-Objekte.
Tipp
yield_per ist jetzt auch als Ausführungsoption auf Core-Ebene verfügbar, wie ausführlich unter Verwendung von Server Side Cursors (auch Stream Results genannt) beschrieben. Dieser Abschnitt beschreibt die Verwendung von yield_per als Ausführungsoption mit einer ORM- Session. Die Option verhält sich in beiden Kontexten so ähnlich wie möglich.
Bei Verwendung mit der ORM muss yield_per entweder über die Methode Executable.execution_options() auf der gegebenen Anweisung oder durch Übergabe an den Parameter Session.execute.execution_options von Session.execute() oder anderen ähnlichen Session-Methoden wie Session.scalars() festgelegt werden. Die typische Verwendung für das Abrufen von ORM-Objekten wird unten gezeigt.
>>> stmt = select(User).execution_options(yield_per=10)
>>> for user_obj in session.scalars(stmt):
... print(user_obj)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
[...] ()
User(id=1, name='spongebob', fullname='Spongebob Squarepants')
User(id=2, name='sandy', fullname='Sandy Cheeks')
...
>>> # ... rows continue ...Der obige Code ist äquivalent zu dem unten stehenden Beispiel, das Connection.execution_options.stream_results und Connection.execution_options.max_row_buffer Core-Level Ausführungsoptionen in Verbindung mit der Methode Result.yield_per() von Result verwendet.
# equivalent code
>>> stmt = select(User).execution_options(stream_results=True, max_row_buffer=10)
>>> for user_obj in session.scalars(stmt).yield_per(10):
... print(user_obj)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
[...] ()
User(id=1, name='spongebob', fullname='Spongebob Squarepants')
User(id=2, name='sandy', fullname='Sandy Cheeks')
...
>>> # ... rows continue ...yield_per wird auch häufig in Kombination mit der Methode Result.partitions() verwendet, die Zeilen in gruppierten Partitionen iteriert. Die Größe jeder Partition entspricht standardmäßig dem Integerwert, der an yield_per übergeben wird, wie im folgenden Beispiel gezeigt.
>>> stmt = select(User).execution_options(yield_per=10)
>>> for partition in session.scalars(stmt).partitions():
... for user_obj in partition:
... print(user_obj)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
[...] ()
User(id=1, name='spongebob', fullname='Spongebob Squarepants')
User(id=2, name='sandy', fullname='Sandy Cheeks')
...
>>> # ... rows continue ...Die Ausführungsoption yield_per ist **nicht kompatibel** mit dem "Subquery" Eager Loading oder dem "Joined" Eager Loading bei Verwendung von Sammlungen. Sie ist möglicherweise kompatibel mit "Select in" Eager Loading, vorausgesetzt, der Treiber unterstützt mehrere unabhängige Cursors.
Zusätzlich ist die Ausführungsoption yield_per nicht kompatibel mit der Methode Result.unique(); da diese Methode darauf basiert, einen vollständigen Satz von Identitäten für alle Zeilen zu speichern, würde sie notwendigerweise den Zweck der Verwendung von yield_per untergraben, nämlich die Verarbeitung einer beliebig großen Anzahl von Zeilen.
Geändert in Version 1.4.6: Es wird eine Ausnahme ausgelöst, wenn ORM-Zeilen aus einem Result-Objekt abgerufen werden, das die Filterfunktion Result.unique() verwendet, während gleichzeitig die Ausführungsoption yield_per verwendet wird.
Bei Verwendung des Legacy- Query-Objekts mit ORM-Verwendung im 1.x-Stil hat die Methode Query.yield_per() das gleiche Ergebnis wie die Ausführungsoption yield_per.
Identitätstoken¶
Deep Alchemy
Diese Option ist eine Funktion für fortgeschrittene Anwendungsfälle und ist hauptsächlich für die Verwendung mit der Erweiterung Horizontal Sharding gedacht. Für typische Fälle des Ladens von Objekten mit identischen Primärschlüsseln aus verschiedenen "Shards" oder Partitionen sollten Sie zuerst einzelne Session-Objekte pro Shard verwenden.
Das "Identitätstoken" ist ein beliebiger Wert, der innerhalb des Identitätsschlüssels von neu geladenen Objekten assoziiert werden kann. Dieses Element existiert in erster Linie zur Unterstützung von Erweiterungen, die zeilenweises "Sharding" durchführen, bei dem Objekte aus beliebigen Replikaten einer bestimmten Datenbanktabelle geladen werden können, die jedoch überlappende Primärschlüsselwerte haben. Der Hauptverbraucher von "Identitätstoken" ist die Erweiterung Horizontal Sharding, die ein allgemeines Framework für die Persistenz von Objekten in mehreren "Shards" einer bestimmten Datenbanktabelle bietet.
Die Ausführungsoption identity_token kann pro Abfrage verwendet werden, um dieses Token direkt zu beeinflussen. Durch direkte Verwendung können Sie eine Session mit mehreren Instanzen eines Objekts füllen, die den gleichen Primärschlüssel und die gleiche Quelltabelle haben, aber unterschiedliche "Identitäten".
Ein solches Beispiel ist das Füllen einer Session mit Objekten, die aus Tabellen mit demselben Namen in verschiedenen Schemas stammen, unter Verwendung der Funktion zur Übersetzung von Schemanamen, die die Wahl des Schemas im Geltungsbereich von Abfragen beeinflussen kann. Gegeben sei eine Zuordnung wie
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
class Base(DeclarativeBase):
pass
class MyTable(Base):
__tablename__ = "my_table"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]Der Standard-"Schema"-Name für die obige Klasse ist None, was bedeutet, dass keine Schema-Qualifizierung in SQL-Anweisungen geschrieben wird. Wenn wir jedoch Connection.execution_options.schema_translate_map verwenden und None auf ein alternatives Schema abbilden, können wir Instanzen von MyTable in zwei verschiedene Schemas platzieren.
engine = create_engine(
"postgresql+psycopg://scott:tiger@localhost/test",
)
with Session(
engine.execution_options(schema_translate_map={None: "test_schema"})
) as sess:
sess.add(MyTable(name="this is schema one"))
sess.commit()
with Session(
engine.execution_options(schema_translate_map={None: "test_schema_2"})
) as sess:
sess.add(MyTable(name="this is schema two"))
sess.commit()Die beiden obigen Blöcke erstellen jeweils ein Session-Objekt, das mit einer anderen Schema-Übersetzungskarte verknüpft ist, und eine Instanz von MyTable wird sowohl in test_schema.my_table als auch in test_schema_2.my_table gespeichert.
Die obigen Session-Objekte sind unabhängig. Wenn wir beide Objekte in einer Transaktion speichern wollten, müssten wir die Erweiterung Horizontal Sharding dafür verwenden.
Wir können jedoch das Abfragen dieser Objekte in einer einzigen Session wie folgt veranschaulichen.
with Session(engine) as sess:
obj1 = sess.scalar(
select(MyTable)
.where(MyTable.id == 1)
.execution_options(
schema_translate_map={None: "test_schema"},
identity_token="test_schema",
)
)
obj2 = sess.scalar(
select(MyTable)
.where(MyTable.id == 1)
.execution_options(
schema_translate_map={None: "test_schema_2"},
identity_token="test_schema_2",
)
)Sowohl obj1 als auch obj2 sind voneinander verschieden. Sie beziehen sich jedoch beide auf den Primärschlüssel-ID 1 für die Klasse MyTable und sind dennoch unterschiedlich. So kommt das identity_token ins Spiel, was wir bei der Inspektion jedes Objekts sehen können, indem wir InstanceState.key betrachten, um die beiden unterschiedlichen Identitätstoken anzuzeigen.
>>> from sqlalchemy import inspect
>>> inspect(obj1).key
(<class '__main__.MyTable'>, (1,), 'test_schema')
>>> inspect(obj2).key
(<class '__main__.MyTable'>, (1,), 'test_schema_2')Die obige Logik findet automatisch statt, wenn die Erweiterung Horizontal Sharding verwendet wird.
Neu in Version 2.0.0rc1: - hinzugefügt die ORM-Ausführungsoption identity_token.
Siehe auch
Horizontal Sharding - im Abschnitt ORM Examples. Siehe das Skript separate_schema_translates.py für eine Demonstration des obigen Anwendungsfalls mit der vollständigen Sharding-API.
Entitäten und Spalten aus ORM-aktivierten SELECT- und DML-Anweisungen inspizieren¶
Das Konstrukt select() sowie die Konstrukte insert(), update() und delete() (für letztere DML-Konstrukte, ab SQLAlchemy 1.4.33) unterstützen die Fähigkeit, die Entitäten zu inspizieren, gegen die diese Anweisungen erstellt werden, sowie die Spalten und Datentypen, die in einem Ergebnisset zurückgegeben würden.
Für ein Select-Objekt sind diese Informationen über das Attribut Select.column_descriptions verfügbar. Dieses Attribut funktioniert genauso wie das Legacy-Attribut Query.column_descriptions. Das zurückgegebene Format ist eine Liste von Dictionaries.
>>> from pprint import pprint
>>> user_alias = aliased(User, name="user2")
>>> stmt = select(User, User.id, user_alias)
>>> pprint(stmt.column_descriptions)
[{'aliased': False,
'entity': <class 'User'>,
'expr': <class 'User'>,
'name': 'User',
'type': <class 'User'>},
{'aliased': False,
'entity': <class 'User'>,
'expr': <....InstrumentedAttribute object at ...>,
'name': 'id',
'type': Integer()},
{'aliased': True,
'entity': <AliasedClass ...; User>,
'expr': <AliasedClass ...; User>,
'name': 'user2',
'type': <class 'User'>}]Wenn Select.column_descriptions mit Nicht-ORM-Objekten wie einfachen Table- oder Column-Objekten verwendet wird, enthalten die Einträge grundlegende Informationen über einzelne Spalten, die in allen Fällen zurückgegeben werden.
>>> stmt = select(user_table, address_table.c.id)
>>> pprint(stmt.column_descriptions)
[{'expr': Column('id', Integer(), table=<user_account>, primary_key=True, nullable=False),
'name': 'id',
'type': Integer()},
{'expr': Column('name', String(), table=<user_account>, nullable=False),
'name': 'name',
'type': String()},
{'expr': Column('fullname', String(), table=<user_account>),
'name': 'fullname',
'type': String()},
{'expr': Column('id', Integer(), table=<address>, primary_key=True, nullable=False),
'name': 'id_1',
'type': Integer()}]Geändert in Version 1.4.33: Das Attribut Select.column_descriptions gibt jetzt einen Wert zurück, wenn es gegen ein Select verwendet wird, das nicht ORM-fähig ist. Zuvor würde dies NotImplementedError auslösen.
Für insert(), update() und delete() Konstrukte gibt es zwei separate Attribute. Eines ist UpdateBase.entity_description, das Informationen über die primäre ORM-Entität und die Datenbanktabelle zurückgibt, die das DML-Konstrukt beeinflussen würde
>>> from sqlalchemy import update
>>> stmt = update(User).values(name="somename").returning(User.id)
>>> pprint(stmt.entity_description)
{'entity': <class 'User'>,
'expr': <class 'User'>,
'name': 'User',
'table': Table('user_account', ...),
'type': <class 'User'>}Tipp
Die UpdateBase.entity_description enthält einen Eintrag "table", der tatsächlich die Tabelle ist, in die eingefügt, aktualisiert oder aus der gelöscht werden soll, was nicht immer dasselbe ist wie das SQL-“selektierbare”, auf das die Klasse abgebildet werden kann. In einem Joined-Table-Inheritance-Szenario bezieht sich "table" beispielsweise auf die lokale Tabelle für die gegebene Entität.
Das andere ist UpdateBase.returning_column_descriptions, das Informationen über die Spalten in der RETURNING-Sammlung liefert, in einer Weise, die grob der von Select.column_descriptions ähnelt.
>>> pprint(stmt.returning_column_descriptions)
[{'aliased': False,
'entity': <class 'User'>,
'expr': <sqlalchemy.orm.attributes.InstrumentedAttribute ...>,
'name': 'id',
'type': Integer()}]Neu in Version 1.4.33: Attribute UpdateBase.entity_description und UpdateBase.returning_column_descriptions hinzugefügt.
Zusätzliche ORM-API-Konstrukte¶
| Objektname | Beschreibung |
|---|---|
aliased(element[, alias, name, flat, ...]) |
Erzeugt einen Alias für das gegebene Element, normalerweise eine |
Repräsentiert eine "aliassierte" Form einer abgebildeten Klasse zur Verwendung mit Query. |
|
Bietet eine Inspektionsschnittstelle für ein |
|
Eine Gruppierung von SQL-Ausdrücken, die von einer |
|
join(left, right[, onclause, isouter, ...]) |
Erzeugt einen Inner Join zwischen linken und rechten Klauseln. |
outerjoin(left, right[, onclause, full]) |
Erzeugt einen Left Outer Join zwischen linken und rechten Klauseln. |
with_loader_criteria(entity_or_base, where_criteria[, loader_only, include_aliases, ...]) |
Fügt der Ladung für alle Vorkommen einer bestimmten Entität zusätzliche WHERE-Kriterien hinzu. |
with_parent(instance, prop[, from_entity]) |
Erstellt ein Filterkriterium, das die primäre Entität dieser Abfrage mit der gegebenen verwandten Instanz über die konfigurierte |
- function sqlalchemy.orm.aliased(element: _EntityType[_O] | FromClause, alias: FromClause | None = None, name: str | None = None, flat: bool = False, adapt_on_names: bool = False) → AliasedClass[_O] | FromClause | AliasedType[_O]¶
Erzeugt einen Alias für das gegebene Element, normalerweise eine
AliasedClass-Instanz.Z. B.
my_alias = aliased(MyClass) stmt = select(MyClass, my_alias).filter(MyClass.id > my_alias.id) result = session.execute(stmt)
Die Funktion
aliased()wird verwendet, um eine Ad-hoc-Abbildung einer abgebildeten Klasse auf ein neues auswählbares Element zu erstellen. Standardmäßig wird ein auswählbares Element aus dem normalerweise abgebildeten auswählbaren Element (typischerweise eineTable) mithilfe der MethodeFromClause.alias()generiert.aliased()kann jedoch auch verwendet werden, um die Klasse mit einer neuenselect()-Anweisung zu verknüpfen. Außerdem ist die Funktionwith_polymorphic()eine Variante vonaliased(), die dazu dient, ein sogenanntes "polymorphes auswählbares" anzugeben, das die Vereinigung mehrerer geerbter Unterklassen gleichzeitig darstellt.Der Einfachheit halber akzeptiert die Funktion
aliased()auch einfacheFromClause-Konstrukte wie eineTableoderselect()-Konstrukt. In diesen Fällen wird die MethodeFromClause.alias()auf dem Objekt aufgerufen und das neueAlias-Objekt zurückgegeben. Das zurückgegebeneAliasist in diesem Fall nicht ORM-abgebildet.Siehe auch
- Parameter:
element¶ – das abzubildende Element. Ist normalerweise eine abgebildete Klasse, kann aber aus Bequemlichkeitsgründen auch ein
FromClause-Element sein.alias¶ – Optionales auswählbares Element, auf das das Element abgebildet werden soll. Dies wird normalerweise verwendet, um das Objekt mit einer Unterabfrage zu verknüpfen, und sollte ein aliassiertes Select-Konstrukt sein, wie es aus der Methode
Query.subquery()oder den MethodenSelect.subquery()oderSelect.alias()desselect()-Konstrukts erzeugt werden würde.name¶ – Optionaler Zeichenkettenname für den Alias, falls nicht durch den Parameter
aliasangegeben. Der Name ist unter anderem der Attributname, der über Tupel erreichbar ist, die von einemQuery-Objekt zurückgegeben werden. Nicht unterstützt bei der Erstellung von Aliasen vonJoin-Objekten.flat¶ –
Boolean, wird an den Aufruf von
FromClause.alias()weitergegeben, sodass Aliase vonJoin-Objekten die einzelnen Tabellen innerhalb des Joins aliassieren, anstatt eine Unterabfrage zu erstellen. Dies wird von allen modernen Datenbanken im Hinblick auf rechts verschachtelte Joins im Allgemeinen unterstützt und führt im Allgemeinen zu effizienteren Abfragen.Wenn
aliased.flatmitaliased.namekombiniert wird, benennen die resultierenden Joins einzelne Tabellen mit einem Benennungsschema ähnlich wie<prefix>_<tablename>. Dieses Benennungsschema dient nur der Sichtbarkeit/Fehlersuche und das spezifische Schema kann ohne Vorankündigung geändert werden.Neu in Version 2.0.32: Unterstützung für die Kombination von
aliased.namemitaliased.flathinzugefügt. Zuvor wurde hierbeiNotImplementedErrorausgelöst.adapt_on_names¶ –
Wenn True, wird eine liberalere "Übereinstimmung" verwendet, wenn die abgebildeten Spalten der ORM-Entität mit denen des gegebenen auswählbaren Elements abgeglichen werden – ein namensbasierter Abgleich wird durchgeführt, wenn das gegebene auswählbare Element keine Spalte hat, die einer der Entität entspricht. Der Anwendungsfall dafür ist die Verknüpfung einer Entität mit einem abgeleiteten auswählbaren Element, wie z. B. einem, das Aggregatfunktionen verwendet.
class UnitPrice(Base): __tablename__ = "unit_price" ... unit_id = Column(Integer) price = Column(Numeric) aggregated_unit_price = ( Session.query(func.sum(UnitPrice.price).label("price")) .group_by(UnitPrice.unit_id) .subquery() ) aggregated_unit_price = aliased( UnitPrice, alias=aggregated_unit_price, adapt_on_names=True )
Oben beziehen sich Funktionen auf
aggregated_unit_price, die sich auf.pricebeziehen, auf die Spaltefunc.sum(UnitPrice.price).label('price'), da sie nach dem Namen "price" abgeglichen wird. Normalerweise hätte die Funktion "price" keine "Spaltenentsprechung" zur tatsächlichen SpalteUnitPrice.price, da sie keine Proxy der Originalspalte ist.
- class sqlalchemy.orm.util.AliasedClass¶
Repräsentiert eine "aliassierte" Form einer abgebildeten Klasse zur Verwendung mit Query.
Das ORM-Äquivalent eines
alias()-Konstrukts, dieses Objekt ahmt die abgebildete Klasse mithilfe eines__getattr__-Schemas nach und behält einen Verweis auf ein echtesAlias-Objekt.Ein Hauptzweck von
AliasedClassist es, als Alternative innerhalb einer von der ORM generierten SQL-Anweisung zu dienen, sodass eine vorhandene abgebildete Entität in mehreren Kontexten verwendet werden kann. Ein einfaches Beispiel# find all pairs of users with the same name user_alias = aliased(User) session.query(User, user_alias).join( (user_alias, User.id > user_alias.id) ).filter(User.name == user_alias.name)
AliasedClasskann auch eine vorhandene abgebildete Klasse auf ein völlig neues auswählbares Element abbilden, vorausgesetzt, dieses auswählbare Element ist spaltenkompatibel mit dem vorhandenen abgebildeten auswählbaren Element, und es kann auch in einer Abbildung als Ziel einerrelationship()konfiguriert werden. Beispiele finden Sie unter den nachfolgenden Links.Das Objekt
AliasedClasswird typischerweise mithilfe der Funktionaliased()konstruiert. Es wird auch mit zusätzlicher Konfiguration erzeugt, wenn die Funktionwith_polymorphic()verwendet wird.Das resultierende Objekt ist eine Instanz von
AliasedClass. Dieses Objekt implementiert ein Attributschema, das dieselbe Attribut- und Methodenschnittstelle wie die ursprüngliche abgebildete Klasse erzeugt, wodurchAliasedClassmit jeder Attributtechnik kompatibel ist, die auf der ursprünglichen Klasse funktioniert, einschließlich Hybrid-Attributen (siehe Hybrid Attributes).Die
AliasedClasskann mithilfe voninspect()auf ihren zugrunde liegendenMapper, aliassierten auswählbaren Elementen und anderen Informationen geprüft werden.from sqlalchemy import inspect my_alias = aliased(MyClass) insp = inspect(my_alias)
Das resultierende Inspektionsobjekt ist eine Instanz von
AliasedInsp.Siehe auch
Klassensignatur
class
sqlalchemy.orm.AliasedClass(sqlalchemy.inspection.Inspectable,sqlalchemy.orm.ORMColumnsClauseRole)
- class sqlalchemy.orm.util.AliasedInsp¶
Bietet eine Inspektionsschnittstelle für ein
AliasedClass-Objekt.Das Objekt
AliasedInspwird zurückgegeben, wenn einAliasedClassmithilfe der Funktioninspect()übergeben wird.from sqlalchemy import inspect from sqlalchemy.orm import aliased my_alias = aliased(MyMappedClass) insp = inspect(my_alias)
Attribute von
AliasedInspumfassenentity- die dargestellteAliasedClass.mapper- derMapper, der die zugrunde liegende Klasse abbildet.selectable- dasAlias-Konstrukt, das letztendlich eine aliassierteTableoder einSelect-Konstrukt darstellt.name- der Name des Alias. Wird auch als Attributname verwendet, wenn er in einem Ergebnis-Tupel vonQueryzurückgegeben wird.with_polymorphic_mappers- Sammlung vonMapper-Objekten, die alle Mapper angeben, die im Select-Konstrukt für dieAliasedClassausgedrückt werden.polymorphic_on- eine alternative Spalte oder ein SQL-Ausdruck, der als "Diskriminator" für eine polymorphe Ladung verwendet wird.
Siehe auch
Klassensignatur
class
sqlalchemy.orm.AliasedInsp(sqlalchemy.orm.ORMEntityColumnsClauseRole,sqlalchemy.orm.ORMFromClauseRole,sqlalchemy.sql.cache_key.HasCacheKey,sqlalchemy.orm.base.InspectionAttr,sqlalchemy.util.langhelpers.MemoizedSlots,sqlalchemy.inspection.Inspectable,typing.Generic)
- class sqlalchemy.orm.Bundle¶
Eine Gruppierung von SQL-Ausdrücken, die von einer
Queryunter einem Namespace zurückgegeben werden.Das
Bundleerlaubt im Wesentlichen das Verschachteln von Tupel-basierten Ergebnissen, die von einem spaltenorientiertenQuery-Objekt zurückgegeben werden. Es ist auch durch einfaches Unterklassieren erweiterbar, wobei die primäre Möglichkeit zur Überschreibung darin besteht, wie die Menge der Ausdrücke zurückgegeben werden soll, was Post-Processing sowie benutzerdefinierte Rückgabetypen ermöglicht, ohne ORM-identitätsabgebildete Klassen einzubeziehen.Mitglieder
__init__(), c, columns, create_row_processor(), is_aliased_class, is_bundle, is_clause_element, is_mapper, label(), single_entity
Klassensignatur
class
sqlalchemy.orm.Bundle(sqlalchemy.orm.ORMColumnsClauseRole,sqlalchemy.sql.annotation.SupportsCloneAnnotations,sqlalchemy.sql.cache_key.MemoizedHasCacheKey,sqlalchemy.inspection.Inspectable,sqlalchemy.orm.base.InspectionAttr)-
method
sqlalchemy.orm.Bundle.__init__(name: str, *exprs: _ColumnExpressionArgument[Any], **kw: Any)¶ Konstruiert ein neues
Bundle.z. B.
bn = Bundle("mybundle", MyClass.x, MyClass.y) for row in session.query(bn).filter(bn.c.x == 5).filter(bn.c.y == 4): print(row.mybundle.x, row.mybundle.y)
-
attribute
sqlalchemy.orm.Bundle.c: ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]¶ Ein Alias für
Bundle.columns.
-
attribute
sqlalchemy.orm.Bundle.columns: ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]¶ Ein Namespace von SQL-Ausdrücken, auf die sich dieses
Bundlebezieht.z. B.
bn = Bundle("mybundle", MyClass.x, MyClass.y) q = sess.query(bn).filter(bn.c.x == 5)
Verschachtelung von Bundles wird ebenfalls unterstützt
b1 = Bundle( "b1", Bundle("b2", MyClass.a, MyClass.b), Bundle("b3", MyClass.x, MyClass.y), ) q = sess.query(b1).filter(b1.c.b2.c.a == 5).filter(b1.c.b3.c.y == 9)
Siehe auch
-
methode
sqlalchemy.orm.Bundle.create_row_processor(query: Select[Any], procs: Sequence[Callable[[Row[Any]], Any]], labels: Sequence[str]) → Callable[[Row[Any]], Any]¶ Erzeugt die „Zeilenverarbeitungs“-Funktion für dieses
Bundle.Kann von Unterklassen überschrieben werden, um benutzerdefinierte Verhaltensweisen bei abgerufenen Ergebnissen bereitzustellen. Die Methode erhält zur Abfragezeit das Anweisungsobjekt und eine Menge von „Zeilenprozessor“-Funktionen; diese Prozessorfunktionen geben bei einer Ergebniszeile den einzelnen Attributwert zurück, der dann in jede beliebige Rückgabedatenstruktur angepasst werden kann.
Das folgende Beispiel veranschaulicht das Ersetzen der üblichen
Row-Rückgabestruktur durch ein direktes Python-Dictionaryfrom sqlalchemy.orm import Bundle class DictBundle(Bundle): def create_row_processor(self, query, procs, labels): "Override create_row_processor to return values as dictionaries" def proc(row): return dict(zip(labels, (proc(row) for proc in procs))) return proc
Ein Ergebnis aus dem obigen
Bundlegibt Dictionary-Werte zurückbn = DictBundle("mybundle", MyClass.data1, MyClass.data2) for row in session.execute(select(bn)).where(bn.c.data1 == "d1"): print(row.mybundle["data1"], row.mybundle["data2"])
-
attribut
sqlalchemy.orm.Bundle.is_aliased_class = False¶ True, wenn dieses Objekt eine Instanz von
AliasedClassist.
-
attribut
sqlalchemy.orm.Bundle.is_bundle = True¶ True, wenn dieses Objekt eine Instanz von
Bundleist.
-
attribut
sqlalchemy.orm.Bundle.is_clause_element = False¶ True, wenn dieses Objekt eine Instanz von
ClauseElementist.
-
attribut
sqlalchemy.orm.Bundle.is_mapper = False¶ True, wenn dieses Objekt eine Instanz von
Mapperist.
-
methode
sqlalchemy.orm.Bundle.label(name)¶ Bietet eine Kopie dieses
Bundlemit einem neuen Label.
-
attribut
sqlalchemy.orm.Bundle.single_entity = False¶ Wenn True, werden Abfragen nach einem einzelnen Bundle als einzelne Entität zurückgegeben, anstatt als Element in einem Schlüssel-Tupel.
-
method
- funktion sqlalchemy.orm.with_loader_criteria(entity_or_base: _EntityType[Any], where_criteria: _ColumnExpressionArgument[bool] | Callable[[Any], _ColumnExpressionArgument[bool]], loader_only: bool = False, include_aliases: bool = False, propagate_to_loaders: bool = True, track_closure_variables: bool = True) → LoaderCriteriaOption¶
Fügt der Ladung für alle Vorkommen einer bestimmten Entität zusätzliche WHERE-Kriterien hinzu.
Neu in Version 1.4.
Die Option
with_loader_criteria()dient dazu, bestimmte Kriterien für eine bestimmte Art von Entität in einer Abfrage hinzuzufügen, und zwar **global**, d. h. sie gilt für die Entität, wie sie in der SELECT-Abfrage sowie in allen Unterabfragen, Join-Bedingungen und Beziehungs-Loads erscheint, einschließlich sowohl von Eager- als auch von Lazy-Loadern, ohne dass sie in einem bestimmten Teil der Abfrage angegeben werden muss. Die Rendering-Logik verwendet dasselbe System wie Single Table Inheritance, um sicherzustellen, dass ein bestimmter Diskriminator einer Tabelle zugeordnet wird.Beispielsweise können wir mit Abfragen im „2.0-Stil“ die Art und Weise einschränken, wie die Sammlung
User.addressesgeladen wird, unabhängig von der Art des verwendeten Ladens.from sqlalchemy.orm import with_loader_criteria stmt = select(User).options( selectinload(User.addresses), with_loader_criteria(Address, Address.email_address != "foo"), )
Oben wendet der „selectinload“ für
User.addressesdie gegebenen Filterkriterien auf die WHERE-Klausel an.Ein weiteres Beispiel, bei dem die Filterung auf die ON-Klausel des Joins angewendet wird, in diesem Beispiel mit Abfragen im „1.x-Stil“.
q = ( session.query(User) .outerjoin(User.addresses) .options(with_loader_criteria(Address, Address.email_address != "foo")) )
Der Hauptzweck von
with_loader_criteria()ist die Verwendung imSessionEvents.do_orm_execute()Event-Handler, um sicherzustellen, dass alle Vorkommen einer bestimmten Entität auf eine bestimmte Weise gefiltert werden, z. B. zur Zugriffssteuerungsrolle. Es kann auch verwendet werden, um Kriterien für Beziehungs-Loads anzuwenden. Im folgenden Beispiel können wir bestimmte Regeln auf alle Abfragen anwenden, die von einer bestimmtenSessionausgegeben werden.session = Session(bind=engine) @event.listens_for("do_orm_execute", session) def _add_filtering_criteria(execute_state): if ( execute_state.is_select and not execute_state.is_column_load and not execute_state.is_relationship_load ): execute_state.statement = execute_state.statement.options( with_loader_criteria( SecurityRole, lambda cls: cls.role.in_(["some_role"]), include_aliases=True, ) )
Im obigen Beispiel fängt das Ereignis
SessionEvents.do_orm_execute()alle mit derSessionausgegebenen Abfragen ab. Für Abfragen, die SELECT-Anweisungen sind und keine Attribut- oder Beziehungs-Loads sind, wird der Abfrage eine benutzerdefinierte Optionwith_loader_criteria()hinzugefügt. Die Optionwith_loader_criteria()wird in der gegebenen Anweisung verwendet und auch automatisch an alle von dieser Abfrage abgeleiteten Beziehungs-Loads weitergegeben.Das als Kriterium übergebene Argument ist ein
lambda, das eincls-Argument akzeptiert. Die gegebene Klasse wird erweitert, um alle zugeordneten Unterklassen einzuschließen, und muss selbst keine zugeordnete Klasse sein.Tipp
Bei der Verwendung der Option
with_loader_criteria()in Verbindung mit der Ladeoptioncontains_eager()ist zu beachten, dasswith_loader_criteria()nur den Teil der Abfrage beeinflusst, der bestimmt, welche SQL-Befehle in Bezug auf die WHERE- und FROM-Klauseln gerendert werden. Die Optioncontains_eager()beeinflusst nicht das Rendering der SELECT-Anweisung außerhalb der Spaltenklausel und hat daher keine Wechselwirkung mit der Optionwith_loader_criteria(). Die Funktionsweise voncontains_eager()ist jedoch dafür gedacht, mit einer Abfrage verwendet zu werden, die bereits einige der zusätzlichen Entitäten auswählt, wobeiwith_loader_criteria()ihre zusätzlichen Kriterien anwenden kann.Im folgenden Beispiel, unter der Annahme einer Zuordnungsbeziehung als
A -> A.bs -> B, beeinflusst die gegebene Optionwith_loader_criteria()die Art und Weise, wie der JOIN gerendert wird.stmt = ( select(A) .join(A.bs) .options(contains_eager(A.bs), with_loader_criteria(B, B.flag == 1)) )
Oben beeinflusst die gegebene Option
with_loader_criteria()die ON-Klausel des Joins, der durch.join(A.bs)angegeben wird, also wird er wie erwartet angewendet. Die Optioncontains_eager()bewirkt, dass Spalten vonBzur Spaltenklausel hinzugefügt werden.SELECT b.id, b.a_id, b.data, b.flag, a.id AS id_1, a.data AS data_1 FROM a JOIN b ON a.id = b.a_id AND b.flag = :flag_1
Die Verwendung der Option
contains_eager()innerhalb der obigen Anweisung hat keine Auswirkung auf das Verhalten der Optionwith_loader_criteria(). Wenn die Optioncontains_eager()weggelassen würde, wäre die SQL-Anweisung in Bezug auf die FROM- und WHERE-Klauseln dieselbe, wobeiwith_loader_criteria()weiterhin seine Kriterien zur ON-Klausel des Joins hinzufügt. Die Hinzufügung voncontains_eager()beeinflusst nur die Spaltenklausel, indem zusätzliche Spalten zubhinzugefügt werden, die dann vom ORM verarbeitet werden, umB-Instanzen zu erzeugen.Warnung
Die Verwendung eines Lambdas innerhalb des Aufrufs von
with_loader_criteria()wird nur **einmal pro eindeutiger Klasse** aufgerufen. Benutzerdefinierte Funktionen sollten nicht innerhalb dieses Lambdas aufgerufen werden. Siehe Verwendung von Lambdas zur Erzielung erheblicher Geschwindigkeitssteigerungen bei der Erzeugung von Anweisungen für einen Überblick über die „Lambda-SQL“-Funktion, die nur für fortgeschrittene Anwendungsfälle bestimmt ist.- Parameter:
entity_or_base¶ – eine zugeordnete Klasse oder eine Klasse, die eine Oberklasse einer bestimmten Gruppe von zugeordneten Klassen ist, auf die die Regel angewendet wird.
where_criteria¶ –
ein Core SQL-Ausdruck, der einschränkende Kriterien anwendet. Dies kann auch ein „lambda:“ oder eine Python-Funktion sein, die eine Zielklasse als Argument akzeptiert, wenn die gegebene Klasse eine Basis mit vielen verschiedenen zugeordneten Unterklassen ist.
Hinweis
Um das Pickling zu unterstützen, verwenden Sie eine Modul-weite Python-Funktion, um den SQL-Ausdruck zu erzeugen, anstatt ein Lambda oder einen festen SQL-Ausdruck, die tendenziell nicht pickelbar sind.
include_aliases¶ – wenn True, wird die Regel auch auf
aliased()-Konstrukte angewendet.propagate_to_loaders¶ –
standardmäßig True, gilt für Beziehungs-Loader wie Lazy-Loader. Dies zeigt an, dass das Options-Objekt selbst einschließlich des SQL-Ausdrucks für jede geladene Instanz mitgeführt wird. Setzen Sie auf
False, um zu verhindern, dass das Objekt einzelnen Instanzen zugewiesen wird.Siehe auch
ORM-Abfrageereignisse - enthält Beispiele für die Verwendung von
with_loader_criteria().Globale WHERE/ON-Kriterien hinzufügen - einfaches Beispiel, wie
with_loader_criteria()mit dem EreignisSessionEvents.do_orm_execute()kombiniert werden kann.track_closure_variables¶ –
wenn False, werden Closure-Variablen innerhalb eines Lambda-Ausdrucks nicht als Teil eines Cache-Schlüssels verwendet. Dies ermöglicht die Verwendung komplexerer Ausdrücke innerhalb eines Lambda-Ausdrucks, erfordert jedoch, dass das Lambda sicherstellt, dass es für eine gegebene Klasse bei jeder Ausführung denselben SQL-Ausdruck zurückgibt.
Neu ab Version 1.4.0b2.
- funktion sqlalchemy.orm.join(left: _FromClauseArgument, right: _FromClauseArgument, onclause: _OnClauseArgument | None = None, isouter: bool = False, full: bool = False) → _ORMJoin¶
Erzeugt einen Inner Join zwischen linken und rechten Klauseln.
join()ist eine Erweiterung der Kern-Join-Schnittstelle, die vonjoin()bereitgestellt wird, wobei die linke und rechte wählbare Elemente nicht nur Kern-wählbare Objekte wieTablesein können, sondern auch zugeordnete Klassen oder Instanzen vonAliasedClass. Die „on“-Klausel kann ein SQL-Ausdruck oder ein ORM-zugeordnetes Attribut sein, das auf eine konfigurierterelationship()verweist.join()wird im modernen Sprachgebrauch nicht häufig benötigt, da seine Funktionalität in der von den MethodenSelect.join()undQuery.join()gekapselt ist, die eine signifikante Automatisierung überjoin()hinaus selbst bieten. Die explizite Verwendung vonjoin()mit ORM-aktivierten SELECT-Anweisungen beinhaltet die Verwendung der MethodeSelect.select_from(), wie infrom sqlalchemy.orm import join stmt = ( select(User) .select_from(join(User, Address, User.addresses)) .filter(Address.email_address == "foo@bar.com") )
Im modernen SQLAlchemy kann der obige Join prägnanter geschrieben werden als
stmt = ( select(User) .join(User.addresses) .filter(Address.email_address == "foo@bar.com") )
Warnung
Die direkte Verwendung von
join()funktioniert möglicherweise nicht ordnungsgemäß mit modernen ORM-Optionen wiewith_loader_criteria(). Es wird dringend empfohlen, die idiomatischen Join-Muster zu verwenden, die von Methoden wieSelect.join()undSelect.join_from()bereitgestellt werden, wenn ORM-Joins erstellt werden.Siehe auch
Joins - im ORM Querying Guide für Hintergrundinformationen zu idiomatischen ORM-Join-Mustern
- funktion sqlalchemy.orm.outerjoin(left: _FromClauseArgument, right: _FromClauseArgument, onclause: _OnClauseArgument | None = None, full: bool = False) → _ORMJoin¶
Erzeugt einen Left Outer Join zwischen linken und rechten Klauseln.
Dies ist die „outer join“-Version der Funktion
join()und weist das gleiche Verhalten auf, erzeugt aber einen OUTER JOIN. Weitere Nutzungsdetails finden Sie in der Dokumentation dieser Funktion.
- funktion sqlalchemy.orm.with_parent(instance: object, prop: attributes.QueryableAttribute[Any], from_entity: _EntityType[Any] | None = None) → ColumnElement[bool]¶
Erstellt ein Filterkriterium, das die primäre Entität dieser Abfrage mit der gegebenen verwandten Instanz über die konfigurierte
relationship()-Konfiguration verbindet.Z. B.
stmt = select(Address).where(with_parent(some_user, User.addresses))Das gerenderte SQL ist dasselbe wie das, das gerendert wird, wenn ein Lazy-Loader von der gegebenen übergeordneten Entität für dieses Attribut ausgelöst würde, d.h. der entsprechende Zustand wird vom übergeordneten Objekt in Python übernommen, ohne dass Joins zur übergeordneten Tabelle in der gerenderten Anweisung gerendert werden müssen.
Die gegebene Eigenschaft kann auch
PropComparator.of_type()verwenden, um die linke Seite der Kriterien anzugeben.a1 = aliased(Address) a2 = aliased(Address) stmt = select(a1, a2).where(with_parent(u1, User.addresses.of_type(a2)))
Die obige Verwendung ist äquivalent zur Verwendung des Arguments
from_entity().a1 = aliased(Address) a2 = aliased(Address) stmt = select(a1, a2).where( with_parent(u1, User.addresses, from_entity=a2) )
- Parameter:
instance¶ – Eine Instanz, die eine
relationship()aufweist.property¶ – Klassenbezogenes Attribut, das angibt, welche Beziehung von der Instanz verwendet werden soll, um die Eltern-Kind-Beziehung abzugleichen.
from_entity¶ –
Entität, die als linke Seite betrachtet werden soll. Standardmäßig ist dies die „Null“-Entität der
Queryselbst.Neu seit Version 1.2.
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