SQLAlchemy 2.0 Dokumentation
SQLAlchemy ORM
- ORM Schnellstart
- ORM Abgebildete Klassenkonfiguration
- ORM Mapped Class Übersicht¶
- Klassen mit Deklarativität zuordnen
- Integration mit dataclasses und attrs
- SQL-Ausdrücke als gemappte Attribute
- Ändern des Attributverhaltens
- Zusammengesetzte Spaltentypen
- Abbildung von Klassenhierarchien
- Nicht-traditionelle Zuordnungen
- Konfigurieren eines Versionszählers
- Klassen-Mapping-API
- SQL-Ausdrücke zuordnen
- Beziehungskonfiguration
- ORM Abfragehandbuch
- Verwendung der Sitzung
- Ereignisse und Interna
- ORM Erweiterungen
- ORM Beispiele
Projektversionen
- Vorheriger: ORM Mapped Class Konfiguration
- Nächster: Klassen mit Deklarativem Mappen
- Nach oben: Startseite
- Auf dieser Seite
ORM Mapped Class Übersicht¶
Übersicht über die ORM-Klassenmapping-Konfiguration.
Für Leser, die neu im SQLAlchemy ORM sind und/oder neu in Python im Allgemeinen, wird empfohlen, die ORM Schnellstartanleitung durchzulesen und vorzugsweise das SQLAlchemy Unified Tutorial zu bearbeiten, wo die ORM-Konfiguration zuerst unter Verwendung von ORM Deklarativen Formularen zur Definition von Tabellenmetadaten eingeführt wird.
ORM Mapping-Stile¶
SQLAlchemy bietet zwei verschiedene Stile der Mapper-Konfiguration, die dann weitere Unteroptionen für ihre Einrichtung bieten. Die Variabilität der Mapper-Stile ist vorhanden, um einer vielfältigen Liste von Entwicklerpräferenzen gerecht zu werden, einschließlich des Abstraktionsgrades einer benutzerdefinierten Klasse von der Art und Weise, wie sie auf relationale Schematabellen und -spalten abgebildet werden soll, welche Arten von Klassenhierarchien verwendet werden, einschließlich der Frage, ob benutzerdefinierte Metaklassen-Schemata vorhanden sind oder nicht, und schließlich, ob andere Klasseninstrumentierungsansätze vorhanden sind, wie z. B. die gleichzeitige Verwendung von Python Datenklassen.
In modernem SQLAlchemy ist der Unterschied zwischen diesen Stilen größtenteils oberflächlich; wenn ein bestimmter SQLAlchemy-Konfigurationsstil verwendet wird, um die Absicht, eine Klasse abzubilden, auszudrücken, läuft der interne Prozess der Abbildung der Klasse für jeden Stil größtenteils gleich ab, wobei das Endergebnis immer eine benutzerdefinierte Klasse ist, gegen die ein Mapper konfiguriert ist, mit einer wählbaren Einheit, die typischerweise durch ein Table-Objekt dargestellt wird, und die Klasse selbst wurde instrumentiert, um Verhaltensweisen zu integrieren, die mit relationalen Operationen sowohl auf der Ebene der Klasse als auch auf Instanzen dieser Klasse verbunden sind. Da der Prozess in allen Fällen im Grunde gleich ist, sind Klassen, die aus verschiedenen Stilen abgebildet werden, immer vollständig interoperabel. Das Protokoll MappedClassProtocol kann verwendet werden, um eine gemappte Klasse bei der Verwendung von Typ-Checkern wie mypy anzuzeigen.
Die ursprüngliche Mapping-API wird allgemein als „klassischer“ Stil bezeichnet, während der stärker automatisierte Mapping-Stil als „deklarativer“ Stil bekannt ist. SQLAlchemy bezeichnet diese beiden Mapping-Stile nun als imperatives Mapping und deklaratives Mapping.
Unabhängig vom verwendeten Mapping-Stil stammen alle ORM-Mappings ab SQLAlchemy 1.4 von einem einzigen Objekt namens registry, einer Registrierung von gemappten Klassen. Mithilfe dieser Registrierung kann eine Reihe von Mapper-Konfigurationen als Gruppe finalisiert werden, und Klassen innerhalb einer bestimmten Registrierung können sich während des Konfigurationsprozesses gegenseitig namentlich beziehen.
Geändert in Version 1.4: Deklaratives und klassisches Mapping werden nun als „deklaratives“ und „imperatives“ Mapping bezeichnet und sind intern vereinheitlicht, wobei alle von dem registry-Konstrukt stammen, das eine Sammlung von zusammenhängenden Mappings darstellt.
Deklaratives Mapping¶
Das Deklarative Mapping ist die typische Art und Weise, wie Mappings in modernem SQLAlchemy erstellt werden. Das gängigste Muster ist, zuerst eine Basisklasse mithilfe der DeclarativeBase-Oberklasse zu erstellen. Die resultierende Basisklasse wendet beim Unterklassifizieren den deklarativen Mapping-Prozess auf alle von ihr abgeleiteten Unterklassen an, relativ zu einer bestimmten registry, die standardmäßig lokal zur neuen Basis ist. Das folgende Beispiel veranschaulicht die Verwendung einer deklarativen Basis, die dann in einem deklarativen Tabellenmapping verwendet wird.
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
# declarative base class
class Base(DeclarativeBase):
pass
# an example mapping using the base
class User(Base):
__tablename__ = "user"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
fullname: Mapped[str] = mapped_column(String(30))
nickname: Mapped[Optional[str]]Oben wird die Klasse DeclarativeBase verwendet, um eine neue Basisklasse zu generieren (in der SQLAlchemy-Dokumentation wird sie typischerweise als Base bezeichnet, kann aber jeden gewünschten Namen haben), von der neue abzubildende Klassen erben können, wie oben eine neue gemappte Klasse User konstruiert wird.
Geändert in Version 2.0: Die DeclarativeBase-Oberklasse ersetzt die Verwendung der Funktion declarative_base() und der Methoden registry.generate_base(); der Oberklassen-Ansatz integriert sich mit PEP 484-Tools ohne die Verwendung von Plugins. Siehe ORM Deklarative Modelle für Migrationshinweise.
Die Basisklasse bezieht sich auf ein registry-Objekt, das eine Sammlung von zusammenhängenden gemappten Klassen verwaltet, sowie auf ein MetaData-Objekt, das eine Sammlung von Table-Objekten enthält, auf die die Klassen abgebildet werden.
Die wichtigsten deklarativen Mapping-Stile werden in den folgenden Abschnitten näher erläutert.
Verwendung einer deklarativen Basisklasse – deklaratives Mapping mit einer Basisklasse.
Deklaratives Mapping mit einem Dekorator (keine deklarative Basis) – deklaratives Mapping mit einem Dekorator anstelle einer Basisklasse.
Innerhalb des Geltungsbereichs einer deklarativ gemappten Klasse gibt es auch zwei Varianten, wie die Table-Metadaten deklariert werden können. Diese umfassen:
Deklarative Tabelle mit mapped_column() – Tabellenspalten werden inline innerhalb der gemappten Klasse mit der
mapped_column()-Direktive (oder in älterer Form mit demColumn-Objekt direkt) deklariert. Diemapped_column()-Direktive kann auch optional mit Typ-Annotationen unter Verwendung der KlasseMappedkombiniert werden, die einige Details über die gemappten Spalten direkt liefern kann. Die Spaltendirektiven in Kombination mit den Klassenattributen__tablename__und optional__table_args__ermöglichen dem deklarativen Mapping-Prozess die Erstellung einesTable-Objekts, das abgebildet werden soll.Deklarativ mit imperativer Tabelle (auch bekannt als Hybrid-Deklarativ) – Anstatt Tabellenname und Attribute separat anzugeben, wird ein explizit erstelltes
Table-Objekt mit einer Klasse verknüpft, die ansonsten deklarativ abgebildet wird. Dieser Mapping-Stil ist eine Hybridform aus „deklarativem“ und „imperativem“ Mapping und gilt für Techniken wie das Abbilden von Klassen auf reflektierteTable-Objekte, sowie das Abbilden von Klassen auf bestehende Core-Konstrukte wie Joins und Subqueries.
Die Dokumentation für deklaratives Mapping wird unter Klassen mit Deklarativem Mappen fortgesetzt.
Imperatives Mapping¶
Ein imperatives oder klassisches Mapping bezieht sich auf die Konfiguration einer gemappten Klasse mithilfe der Methode registry.map_imperatively(), bei der die Zielklasse keine deklarativen Klassenattribute enthält.
Tipp
Die imperative Mapping-Form ist eine seltenere Mapping-Form, die aus den allerersten SQLAlchemy-Versionen im Jahr 2006 stammt. Sie ist im Wesentlichen ein Mittel, um das deklarative System zu umgehen, um ein „rudimentäreres“ Mapping-System bereitzustellen, und bietet keine modernen Funktionen wie PEP 484-Unterstützung. Daher verwenden die meisten Dokumentationsbeispiele deklarative Formen, und es wird empfohlen, dass neue Benutzer mit der Deklarativen Tabellenkonfiguration beginnen.
Geändert in Version 2.0: Die Methode registry.map_imperatively() wird nun verwendet, um klassische Mappings zu erstellen. Die eigenständige Funktion sqlalchemy.orm.mapper() ist effektiv entfernt.
In „klassischer“ Form werden die Tabellenmetadaten separat mit dem Table-Konstrukt erstellt und dann über die Methode registry.map_imperatively() mit der User-Klasse verknüpft, nachdem eine registry-Instanz eingerichtet wurde. Normalerweise wird eine einzelne Instanz von registry für alle gemappten Klassen gemeinsam genutzt, die miteinander zusammenhängen.
from sqlalchemy import Table, Column, Integer, String, ForeignKey
from sqlalchemy.orm import registry
mapper_registry = registry()
user_table = Table(
"user",
mapper_registry.metadata,
Column("id", Integer, primary_key=True),
Column("name", String(50)),
Column("fullname", String(50)),
Column("nickname", String(12)),
)
class User:
pass
mapper_registry.map_imperatively(User, user_table)Informationen über gemappte Attribute, wie z. B. Beziehungen zu anderen Klassen, werden über das properties-Dictionary bereitgestellt. Das folgende Beispiel veranschaulicht ein zweites Table-Objekt, das einer Klasse namens Address zugeordnet ist, die dann über relationship() mit User verknüpft wird.
address = Table(
"address",
metadata_obj,
Column("id", Integer, primary_key=True),
Column("user_id", Integer, ForeignKey("user.id")),
Column("email_address", String(50)),
)
mapper_registry.map_imperatively(
User,
user,
properties={
"addresses": relationship(Address, backref="user", order_by=address.c.id)
},
)
mapper_registry.map_imperatively(Address, address)Beachten Sie, dass Klassen, die mit dem imperativen Ansatz gemappt werden, vollständig austauschbar mit denen sind, die mit dem deklarativen Ansatz gemappt werden. Beide Systeme erstellen letztendlich dieselbe Konfiguration, bestehend aus einer Table, einer benutzerdefinierten Klasse, die mit einem Mapper-Objekt verknüpft ist. Wenn wir über „das Verhalten von Mapper“ sprechen, schließt dies auch die Verwendung des deklarativen Systems ein – es wird immer noch verwendet, nur im Hintergrund.
Wesentliche Komponenten einer gemappten Klasse¶
Bei allen Mapping-Formen kann das Mapping der Klasse auf viele Arten konfiguriert werden, indem Konstruktionsargumente übergeben werden, die letztendlich Teil des Mapper-Objekts über dessen Konstruktor werden. Die an Mapper gelieferten Parameter stammen aus der gegebenen Mapping-Form, einschließlich der an registry.map_imperatively() übergebenen Parameter für ein imperatives Mapping oder, bei Verwendung des deklarativen Systems, aus einer Kombination der Tabellenspalten, SQL-Ausdrücke und Beziehungen, die zusammen mit Attributen wie __mapper_args__ abgebildet werden.
Es gibt vier allgemeine Klassen von Konfigurationsinformationen, nach denen die Klasse Mapper sucht:
Die zu mappende Klasse¶
Dies ist eine Klasse, die wir in unserer Anwendung erstellen. An die Struktur dieser Klasse gibt es im Allgemeinen keine Einschränkungen. [1] Wenn eine Python-Klasse abgebildet wird, kann es nur **einen** Mapper-Objekt für die Klasse geben. [2]
Beim Mapping mit dem deklarativen Mapping-Stil ist die abzubildende Klasse entweder eine Unterklasse der deklarativen Basisklasse oder wird durch einen Dekorator oder eine Funktion wie registry.mapped() behandelt.
Beim Mapping mit dem imperativen Stil wird die Klasse direkt als Argument map_imperatively.class_ übergeben.
Die Tabelle oder ein anderes FROM-Klausel-Objekt¶
In den allermeisten gängigen Fällen ist dies eine Instanz von Table. Für fortgeschrittenere Anwendungsfälle kann es auch auf jede Art von FromClause-Objekt verweisen, wobei die gängigsten alternativen Objekte das Subquery- und das Join-Objekt sind.
Beim Mapping mit dem deklarativen Mapping-Stil wird die Zielabelle entweder vom deklarativen System basierend auf dem Attribut __tablename__ und den angebotenen Column-Objekten generiert, oder sie wird über das Attribut __table__ festgelegt. Diese beiden Konfigurationsstile werden unter Deklarative Tabelle mit mapped_column() und Deklarativ mit imperativer Tabelle (auch bekannt als Hybrid-Deklarativ) vorgestellt.
Beim Mapping mit dem imperativen Stil wird die Zielabelle positionsabhängig als Argument map_imperatively.local_table übergeben.
Im Gegensatz zur Anforderung „ein Mapper pro Klasse“ für eine gemappte Klasse kann das Table- oder ein anderes FromClause-Objekt, das Gegenstand des Mappings ist, mit beliebiger Anzahl von Mappings assoziiert werden. Der Mapper wendet Modifikationen direkt auf die benutzerdefinierte Klasse an, modifiziert aber das gegebene Table- oder andere FromClause-Objekte in keiner Weise.
Das Eigenschaften-Dictionary¶
Dies ist ein Dictionary aller Attribute, die mit der gemappten Klasse verknüpft werden. Standardmäßig generiert der Mapper Einträge für dieses Dictionary, abgeleitet von der gegebenen Table, in Form von ColumnProperty-Objekten, die jeweils auf eine einzelne Column der gemappten Tabelle verweisen. Das Eigenschaften-Dictionary enthält auch alle anderen Arten von MapperProperty-Objekten, die konfiguriert werden sollen, am häufigsten Instanzen, die vom relationship()-Konstrukt generiert werden.
Beim Mapping mit dem deklarativen Mapping-Stil wird das Eigenschaften-Dictionary vom deklarativen System durch Scannen der abzubildenden Klasse nach geeigneten Attributen generiert. Informationen zu diesem Prozess finden Sie im Abschnitt Definieren von gemappten Eigenschaften mit Deklarativem.
Beim Mapping mit dem imperativen Stil wird das Eigenschaften-Dictionary direkt als Parameter properties an registry.map_imperatively() übergeben, welches es an den Parameter Mapper.properties weiterleitet.
Andere Mapper-Konfigurationsparameter¶
Beim Mapping mit dem deklarativen Mapping-Stil werden zusätzliche Mapper-Konfigurationsargumente über das Klassenattribut __mapper_args__ konfiguriert. Anwendungsbeispiele finden Sie unter Mapper-Konfigurationsoptionen mit Deklarativem.
Beim Mapping mit dem imperativen Stil werden Schlüsselwortargumente an die Methode registry.map_imperatively() übergeben, die sie an die Klasse Mapper weiterleitet.
Die vollständige Bandbreite der akzeptierten Parameter ist unter Mapper dokumentiert.
Verhalten einer gemappten Klasse¶
Über alle Mapping-Stile hinweg, die das registry-Objekt verwenden, sind die folgenden Verhaltensweisen üblich:
Standardkonstruktor¶
Die registry wendet einen Standardkonstruktor, d. h. eine __init__-Methode, auf alle gemappten Klassen an, die nicht explizit ihre eigene __init__-Methode haben. Das Verhalten dieser Methode besteht darin, einen bequemen Schlüsselwortkonstruktor bereitzustellen, der als optionale Schlüsselwortargumente alle benannten Attribute akzeptiert. Z. B.
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "user"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
fullname: Mapped[str]Ein Objekt vom Typ User oben hat einen Konstruktor, der die Erstellung von User-Objekten wie folgt ermöglicht:
u1 = User(name="some name", fullname="some fullname")Tipp
Die Funktion Deklaratives Datenklassen-Mapping bietet eine alternative Möglichkeit zur Generierung einer Standard-__init__()-Methode durch die Verwendung von Python-Datenklassen und ermöglicht eine hochgradig konfigurierbare Konstruktorform.
Warnung
Die __init__()-Methode der Klasse wird nur aufgerufen, wenn das Objekt im Python-Code konstruiert wird, und **nicht, wenn ein Objekt aus der Datenbank geladen oder aktualisiert wird**. Siehe den nächsten Abschnitt Aufrechterhaltung von nicht gemapptem Zustand über Ladevorgänge hinweg für eine Einführung, wie spezielle Logik aufgerufen werden kann, wenn Objekte geladen werden.
Eine Klasse, die eine explizite __init__()-Methode enthält, behält diese Methode bei, und kein Standardkonstruktor wird angewendet.
Um den verwendeten Standardkonstruktor zu ändern, kann ein benutzerdefinierter Python-Callable an den Parameter registry.constructor übergeben werden, der als Standardkonstruktor verwendet wird.
Der Konstruktor gilt auch für imperative Mappings.
from sqlalchemy.orm import registry
mapper_registry = registry()
user_table = Table(
"user",
mapper_registry.metadata,
Column("id", Integer, primary_key=True),
Column("name", String(50)),
)
class User:
pass
mapper_registry.map_imperatively(User, user_table)Die obige Klasse, die wie unter Imperatives Mapping beschrieben imperativ gemappt wurde, wird auch den Standardkonstruktor aufweisen, der mit der registry verknüpft ist.
Neu in Version 1.4: Klassische Mappings unterstützen nun einen standardmäßigen Konfigurations-Konstruktor, wenn sie über die Methode registry.map_imperatively() gemappt werden.
Aufrechterhaltung von nicht gemapptem Zustand über Ladevorgänge hinweg¶
Die __init__()-Methode der gemappten Klasse wird aufgerufen, wenn das Objekt direkt im Python-Code konstruiert wird.
u1 = User(name="some name", fullname="some fullname")Wenn ein Objekt jedoch über die ORM Session geladen wird, wird die __init__()-Methode **nicht** aufgerufen.
u1 = session.scalars(select(User).where(User.name == "some name")).first()Der Grund dafür ist, dass der Vorgang zum Erstellen des Objekts, im obigen Beispiel User, beim Laden aus der Datenbank eher einer **Deserialisierung** ähnelt, wie z. B. Unpickling, anstatt einer anfänglichen Konstruktion. Der Großteil des wichtigen Zustands des Objekts wird nicht zum ersten Mal zusammengesetzt, sondern aus Datenbankzeilen neu geladen.
Daher gibt es, um den Zustand innerhalb des Objekts aufrechtzuerhalten, der nicht Teil der in die Datenbank gespeicherten Daten ist, und der sowohl beim Laden als auch beim Konstruieren von Objekten vorhanden ist, zwei allgemeine Ansätze, die unten beschrieben werden.
Verwenden Sie Python-Deskriptoren wie
@propertyanstelle von Zustand, um Attribute bei Bedarf dynamisch zu berechnen.Für einfache Attribute ist dies der einfachste und am wenigsten fehleranfällige Ansatz. Wenn beispielsweise ein Objekt
PointmitPoint.xundPoint.yein Attribut mit der Summe dieser Attribute wünscht.class Point(Base): __tablename__ = "point" id: Mapped[int] = mapped_column(primary_key=True) x: Mapped[int] y: Mapped[int] @property def x_plus_y(self): return self.x + self.y
Ein Vorteil der Verwendung dynamischer Deskriptoren ist, dass der Wert jedes Mal neu berechnet wird, was bedeutet, dass er den korrekten Wert beibehält, auch wenn sich die zugrunde liegenden Attribute (in diesem Fall
xundy) ändern könnten.Andere Formen des obigen Musters umfassen den Dekorator cached_property der Python-Standardbibliothek (der zwischengespeichert und nicht jedes Mal neu berechnet wird) sowie den Dekorator
hybrid_propertyvon SQLAlchemy, der Attribute ermöglicht, die auch für SQL-Abfragen funktionieren.Zustand beim Laden mit
InstanceEvents.load()festlegen und optional ergänzende MethodenInstanceEvents.refresh()undInstanceEvents.refresh_flush().Dies sind Event-Hooks, die aufgerufen werden, wann immer das Objekt aus der Datenbank geladen oder nach Ablauf erneuert wird. Typischerweise wird nur
InstanceEvents.load()benötigt, da nicht gemappter lokaler Objektzustand von Ablaufoperationen nicht betroffen ist. Zur Überarbeitung des obigenPoint-Beispiels sieht es so aus:from sqlalchemy import event class Point(Base): __tablename__ = "point" id: Mapped[int] = mapped_column(primary_key=True) x: Mapped[int] y: Mapped[int] def __init__(self, x, y, **kw): super().__init__(x=x, y=y, **kw) self.x_plus_y = x + y @event.listens_for(Point, "load") def receive_load(target, context): target.x_plus_y = target.x + target.y
Wenn auch die Refresh-Events verwendet werden, können die Event-Hooks bei Bedarf auf einen einzigen Callable gestapelt werden, wie z. B.:
@event.listens_for(Point, "load") @event.listens_for(Point, "refresh") @event.listens_for(Point, "refresh_flush") def receive_load(target, context, attrs=None): target.x_plus_y = target.x + target.y
Oben wird das Attribut
attrsfür die Eventsrefreshundrefresh_flushvorhanden sein und eine Liste von Attributnamen angeben, die gerade aktualisiert werden.
Laufzeit-Introspektion von gemappten Klassen, Instanzen und Mappern¶
Eine Klasse, die mithilfe von registry gemappt wird, verfügt auch über einige Attribute, die für alle Mappings üblich sind:
Das Attribut
__mapper__verweist auf denMapper, der mit der Klasse assoziiert ist.mapper = User.__mapper__
Dieser
Mapperist auch das, was zurückgegeben wird, wenn die Funktioninspect()gegen die gemappte Klasse verwendet wird.from sqlalchemy import inspect mapper = inspect(User)
Das Attribut
__table__verweist auf dieTable, oder allgemeiner auf dasFromClause-Objekt, auf das die Klasse abgebildet wird.table = User.__table__
Dieses
FromClauseist auch das, was zurückgegeben wird, wenn das AttributMapper.local_tabledesMapperverwendet wird.table = inspect(User).local_table
Bei einer Single-Table-Inheritance-Abbildung, bei der eine Klasse eine Unterklasse ist, die keine eigene Tabelle hat, sind das Attribut
Mapper.local_tablesowie das Attribut.__table__None. Um das "selektierbare" Objekt abzurufen, das tatsächlich bei einer Abfrage für diese Klasse ausgewählt wird, ist dies über das AttributMapper.selectableverfügbar.table = inspect(User).selectable
Inspektion von Mapper-Objekten¶
Wie im vorherigen Abschnitt gezeigt, ist das Mapper-Objekt von jeder abgebildeten Klasse aus zugänglich, unabhängig von der Methode, über das Laufzeitinspektions-API-System. Mit der Funktion inspect() kann man den Mapper von einer abgebildeten Klasse erhalten.
>>> from sqlalchemy import inspect
>>> insp = inspect(User)Detaillierte Informationen sind verfügbar, einschließlich Mapper.columns.
>>> insp.columns
<sqlalchemy.util._collections.OrderedProperties object at 0x102f407f8>Dies ist ein Namespace, der in Listenform oder über einzelne Namen angezeigt werden kann.
>>> list(insp.columns)
[Column('id', Integer(), table=<user>, primary_key=True, nullable=False), Column('name', String(length=50), table=<user>), Column('fullname', String(length=50), table=<user>), Column('nickname', String(length=50), table=<user>)]
>>> insp.columns.name
Column('name', String(length=50), table=<user>)Andere Namespaces umfassen Mapper.all_orm_descriptors, die alle abgebildeten Attribute sowie Hybride und Assoziationsproxys enthält.
>>> insp.all_orm_descriptors
<sqlalchemy.util._collections.ImmutableProperties object at 0x1040e2c68>
>>> insp.all_orm_descriptors.keys()
['fullname', 'nickname', 'name', 'id']Sowie Mapper.column_attrs.
>>> list(insp.column_attrs)
[<ColumnProperty at 0x10403fde0; id>, <ColumnProperty at 0x10403fce8; name>, <ColumnProperty at 0x1040e9050; fullname>, <ColumnProperty at 0x1040e9148; nickname>]
>>> insp.column_attrs.name
<ColumnProperty at 0x10403fce8; name>
>>> insp.column_attrs.name.expression
Column('name', String(length=50), table=<user>)Siehe auch
Inspektion von abgebildeten Instanzen¶
Die Funktion inspect() liefert auch Informationen über Instanzen einer abgebildeten Klasse. Wenn sie auf eine Instanz einer abgebildeten Klasse und nicht auf die Klasse selbst angewendet wird, ist das zurückgegebene Objekt als InstanceState bekannt. Dieses Objekt enthält Links sowohl zum Mapper, der von der Klasse verwendet wird, als auch eine detaillierte Schnittstelle, die Informationen über den Zustand einzelner Attribute innerhalb der Instanz liefert, einschließlich ihres aktuellen Werts und wie dieser mit ihrem aus der Datenbank geladenen Wert zusammenhängt.
Gegeben sei eine Instanz der Klasse User, die aus der Datenbank geladen wurde.
>>> u1 = session.scalars(select(User)).first()Die Funktion inspect() gibt uns ein InstanceState-Objekt zurück.
>>> insp = inspect(u1)
>>> insp
<sqlalchemy.orm.state.InstanceState object at 0x7f07e5fec2e0>Mit diesem Objekt können wir Elemente wie den Mapper sehen.
>>> insp.mapper
<Mapper at 0x7f07e614ef50; User>Die Session, an die das Objekt angebunden ist, falls vorhanden.
>>> insp.session
<sqlalchemy.orm.session.Session object at 0x7f07e614f160>Informationen über den aktuellen Persistenzstatus für das Objekt.
>>> insp.persistent
True
>>> insp.pending
FalseAttributstatusinformationen wie Attribute, die noch nicht geladen wurden oder lazy loaded sind (angenommen, addresses bezieht sich auf eine relationship() auf der abgebildeten Klasse zu einer verwandten Klasse).
>>> insp.unloaded
{'addresses'}Informationen über den aktuellen Status von Attributen in Python, wie z. B. Attribute, die seit dem letzten Flush nicht geändert wurden.
>>> insp.unmodified
{'nickname', 'name', 'fullname', 'id'}sowie spezifische Historie von Änderungen an Attributen seit dem letzten Flush.
>>> insp.attrs.nickname.value
'nickname'
>>> u1.nickname = "new nickname"
>>> insp.attrs.nickname.history
History(added=['new nickname'], unchanged=(), deleted=['nickname'])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