SQLAlchemy 2.0 Dokumentation
SQLAlchemy ORM
- ORM Schnellstart
- ORM Abgebildete Klassenkonfiguration
- Beziehungskonfiguration
- ORM Abfragehandbuch
- Verwendung der Sitzung
- Grundlagen der Session
- Zustandsverwaltung
- Kaskaden¶
- Transaktionen und Verbindungsverwaltung
- Zusätzliche Persistenztechniken
- Kontextuelle/Thread-lokale Sessions
- Abfragen, Objekte und Session-Änderungen mit Events verfolgen
- Session API
- Ereignisse und Interna
- ORM Erweiterungen
- ORM Beispiele
Projektversionen
Kaskaden¶
Mapper unterstützen das Konzept eines konfigurierbaren Kaskaden-Verhaltens bei relationship()-Konstrukten. Dies bezieht sich darauf, wie Operationen, die auf einem "Eltern"-Objekt relativ zu einer bestimmten Session ausgeführt werden, auf Elemente propagiert werden sollen, auf die durch diese Beziehung verwiesen wird (z. B. "Kind"-Objekte), und wird durch die relationship.cascade-Option beeinflusst.
Das Standardverhalten der Kaskade beschränkt sich auf Kaskaden der sogenannten save-update und merge Einstellungen. Die typische "alternative" Einstellung für Kaskaden ist das Hinzufügen der Optionen delete und delete-orphan; diese Einstellungen sind für zugehörige Objekte geeignet, die nur existieren, solange sie an ihren Eltern angehängt sind, und ansonsten gelöscht werden.
Das Kaskadenverhalten wird über die relationship.cascade-Option auf relationship() konfiguriert
class Order(Base):
__tablename__ = "order"
items = relationship("Item", cascade="all, delete-orphan")
customer = relationship("User", cascade="save-update")Um Kaskaden auf einem Backref festzulegen, kann das gleiche Flag mit der Funktion backref() verwendet werden, die ihre Argumente letztendlich wieder an relationship() zurückgibt
class Item(Base):
__tablename__ = "item"
order = relationship(
"Order", backref=backref("items", cascade="all, delete-orphan")
)Der Standardwert von relationship.cascade ist save-update, merge. Die typische alternative Einstellung für diesen Parameter ist entweder all oder häufiger all, delete-orphan. Das Symbol all ist ein Synonym für save-update, merge, refresh-expire, expunge, delete, und seine Verwendung in Verbindung mit delete-orphan bedeutet, dass das Kind-Objekt in allen Fällen seinem Eltern-Objekt folgt und gelöscht wird, sobald es nicht mehr mit diesem Eltern-Objekt verbunden ist.
Warnung
Die Option all für Kaskaden impliziert die Einstellung für die refresh-expire-Kaskade, was bei der Verwendung der Asynchronen E/A (asyncio)-Erweiterung möglicherweise nicht wünschenswert ist, da sie zugehörige Objekte aggressiver verfallen lässt, als es in einem expliziten E/A-Kontext typischerweise angemessen ist. Weitere Hintergrundinformationen finden Sie in den Hinweisen unter Verhindern von impliziten E/A bei Verwendung von AsyncSession.
Die Liste der verfügbaren Werte, die für den Parameter relationship.cascade angegeben werden können, wird in den folgenden Unterabschnitten beschrieben.
save-update¶
save-update Kaskade bedeutet, dass, wenn ein Objekt über Session.add() in eine Session aufgenommen wird, alle über diese relationship() damit verbundenen Objekte ebenfalls in dieselbe Session aufgenommen werden. Angenommen, wir haben ein Objekt user1 mit zwei zugehörigen Objekten address1 und address2.
>>> user1 = User()
>>> address1, address2 = Address(), Address()
>>> user1.addresses = [address1, address2]Wenn wir user1 zu einer Session hinzufügen, werden auch address1 und address2 implizit hinzugefügt.
>>> sess = Session()
>>> sess.add(user1)
>>> address1 in sess
Truesave-update Kaskade beeinflusst auch Attributoperationen für Objekte, die sich bereits in einer Session befinden. Wenn wir ein drittes Objekt, address3, zur Sammlung user1.addresses hinzufügen, wird es Teil des Zustands dieser Session.
>>> address3 = Address()
>>> user1.addresses.append(address3)
>>> address3 in sess
TrueEine save-update Kaskade kann überraschendes Verhalten zeigen, wenn ein Element aus einer Sammlung entfernt oder ein Objekt von einem Skalarattribut getrennt wird. In einigen Fällen können die verwaisten Objekte immer noch in die Session des ehemaligen Elternteils gezogen werden; dies geschieht, damit der Flush-Prozess dieses zugehörige Objekt ordnungsgemäß behandeln kann. Dieser Fall tritt normalerweise nur auf, wenn ein Objekt aus einer Session entfernt und in eine andere eingefügt wird.
>>> user1 = sess1.scalars(select(User).filter_by(id=1)).first()
>>> address1 = user1.addresses[0]
>>> sess1.close() # user1, address1 no longer associated with sess1
>>> user1.addresses.remove(address1) # address1 no longer associated with user1
>>> sess2 = Session()
>>> sess2.add(user1) # ... but it still gets added to the new session,
>>> address1 in sess2 # because it's still "pending" for flush
TrueDie save-update Kaskade ist standardmäßig aktiviert und wird typischerweise als selbstverständlich angesehen; sie vereinfacht den Code, indem sie es ermöglicht, mit einem einzigen Aufruf von Session.add() eine ganze Struktur von Objekten auf einmal innerhalb dieser Session zu registrieren. Obwohl sie deaktiviert werden kann, gibt es normalerweise keinen Grund dazu.
Verhalten der save-update-Kaskade bei bidirektionalen Beziehungen¶
Die save-update Kaskade erfolgt **uni-direktional** im Kontext einer bidirektionalen Beziehung, d.h. wenn die Parameter relationship.back_populates oder relationship.backref verwendet werden, um zwei separate relationship()-Objekte zu erstellen, die aufeinander verweisen.
Ein Objekt, das nicht mit einer Session verbunden ist, wird, wenn es einem Attribut oder einer Sammlung auf einem Eltern-Objekt zugewiesen wird, das mit einer Session verbunden ist, automatisch zu derselben Session hinzugefügt. Dieselbe Operation umgekehrt hat jedoch nicht diesen Effekt; ein Objekt, das nicht mit einer Session verbunden ist, dem ein mit einer Session verbundenes Kind-Objekt zugewiesen wird, führt nicht zu einer automatischen Hinzufügung dieses Eltern-Objekts zur Session. Das gesamte Thema dieses Verhaltens ist als "Kaskaden-Backrefs" bekannt und stellt eine Verhaltensänderung dar, die ab SQLAlchemy 2.0 standardisiert wurde.
Um dies zu veranschaulichen, gegeben eine Abbildung von Order-Objekten, die bidirektional mit einer Reihe von Item-Objekten über die Beziehungen Order.items und Item.order verbunden sind.
mapper_registry.map_imperatively(
Order,
order_table,
properties={"items": relationship(Item, back_populates="order")},
)
mapper_registry.map_imperatively(
Item,
item_table,
properties={"order": relationship(Order, back_populates="items")},
)Wenn eine Order bereits mit einer Session verbunden ist und dann ein Item-Objekt erstellt und zur Sammlung Order.items dieser Order hinzugefügt wird, wird das Item automatisch in dieselbe Session kaskadiert.
>>> o1 = Order()
>>> session.add(o1)
>>> o1 in session
True
>>> i1 = Item()
>>> o1.items.append(i1)
>>> o1 is i1.order
True
>>> i1 in session
TrueOben bedeutet die bidirektionale Natur von Order.items und Item.order, dass das Hinzufügen zu Order.items auch Item.order zuweist. Gleichzeitig ermöglichte die save-update Kaskade, dass das Item-Objekt zur selben Session hinzugefügt wurde, mit der das Eltern-Objekt Order bereits verbunden war.
Wenn jedoch die obige Operation in der **umgekehrten** Richtung durchgeführt wird, bei der Item.order zugewiesen wird und nicht direkt zu Order.item hinzugefügt wird, erfolgt die Kaskadenoperation in die Session **nicht** automatisch, auch wenn die Objektzuweisungen Order.items und Item.order im gleichen Zustand sind wie im vorherigen Beispiel.
>>> o1 = Order()
>>> session.add(o1)
>>> o1 in session
True
>>> i1 = Item()
>>> i1.order = o1
>>> i1 in order.items
True
>>> i1 in session
FalseIn diesem Fall, nachdem das Item-Objekt erstellt und alle gewünschten Zustände darauf gesetzt wurden, sollte es explizit zur Session hinzugefügt werden.
>>> session.add(i1)In älteren SQLAlchemy-Versionen erfolgte die save-update Kaskade in allen Fällen bidirektional. Sie wurde dann optional über eine Option namens cascade_backrefs gemacht. Schließlich wurde in SQLAlchemy 1.4 das alte Verhalten als veraltet eingestuft und die Option cascade_backrefs in SQLAlchemy 2.0 entfernt. Die Begründung ist, dass Benutzer es im Allgemeinen nicht intuitiv finden, dass die Zuweisung eines Attributs an ein Objekt, wie hier die Zuweisung von i1.order = o1, den Persistenzzustand dieses Objekts i1 so verändert, dass es nun in einer Session aussteht, und es häufig zu nachfolgenden Problemen kam, bei denen autoflush das Objekt vorzeitig ausführte und Fehler verursachte, in Fällen, in denen das gegebene Objekt noch konstruiert wurde und nicht in einem Zustand war, der für einen Flush bereit war. Die Option zur Auswahl zwischen uni-direktionalem und bi-direktionalem Verhalten wurde ebenfalls entfernt, da diese Option zwei leicht unterschiedliche Arbeitsweisen schuf, was die allgemeine Lernkurve des ORM sowie die Dokumentations- und Benutzerunterstützungsbelastung erhöhte.
Siehe auch
cascade_backrefs-Verhalten für die Entfernung in 2.0 als veraltet eingestuft - Hintergrund zur Verhaltensänderung bei "cascade backrefs"
delete¶
Die delete Kaskade bedeutet, dass, wenn ein "Eltern"-Objekt zum Löschen markiert wird, seine zugehörigen "Kind"-Objekte ebenfalls zum Löschen markiert werden sollten. Wenn wir zum Beispiel eine Beziehung User.addresses mit konfigurierter delete Kaskade haben.
class User(Base):
# ...
addresses = relationship("Address", cascade="all, delete")Wenn wir die obige Abbildung verwenden, haben wir ein User-Objekt und zwei zugehörige Address-Objekte.
>>> user1 = sess1.scalars(select(User).filter_by(id=1)).first()
>>> address1, address2 = user1.addressesWenn wir user1 zum Löschen markieren, werden nach Abschluss des Flush-Vorgangs auch address1 und address2 gelöscht.
>>> sess.delete(user1)
>>> sess.commit()
DELETE FROM address WHERE address.id = ?
((1,), (2,))
DELETE FROM user WHERE user.id = ?
(1,)
COMMIT
Alternativ, wenn unsere Beziehung User.addresses *keine* delete Kaskade hat, ist das Standardverhalten von SQLAlchemy, stattdessen address1 und address2 von user1 zu trennen, indem ihre Fremdschlüsselreferenz auf NULL gesetzt wird. Unter Verwendung einer Abbildung wie folgt:
class User(Base):
# ...
addresses = relationship("Address")Beim Löschen eines Eltern-Objekts User werden die Zeilen in address nicht gelöscht, sondern stattdessen getrennt.
>>> sess.delete(user1)
>>> sess.commit()
UPDATE address SET user_id=? WHERE address.id = ?
(None, 1)
UPDATE address SET user_id=? WHERE address.id = ?
(None, 2)
DELETE FROM user WHERE user.id = ?
(1,)
COMMIT
delete Kaskade bei Eins-zu-viele-Beziehungen wird oft mit delete-orphan Kaskade kombiniert, die einen DELETE für die zugehörige Zeile ausgibt, wenn das "Kind"-Objekt vom Eltern-Objekt getrennt wird. Die Kombination aus delete und delete-orphan Kaskade deckt beide Situationen ab, in denen SQLAlchemy entscheiden muss, ob ein Fremdschlüsselspalte auf NULL gesetzt oder die Zeile komplett gelöscht werden soll.
Die Funktion funktioniert standardmäßig völlig unabhängig von datenbankseitig konfigurierten FOREIGN KEY-Beschränkungen, die selbst CASCADE-Verhalten konfigurieren können. Um eine effizientere Integration mit dieser Konfiguration zu erreichen, sollten zusätzliche Direktiven verwendet werden, die unter Verwendung von FOREIGN KEY ON DELETE CASCADE mit ORM-Beziehungen beschrieben sind.
Warnung
Beachten Sie, dass das "delete"- und "delete-orphan"-Verhalten des ORM **nur** für die Verwendung der Session.delete()-Methode zur Markierung einzelner ORM-Instanzen zum Löschen im Rahmen des Unit of Work gilt. Es gilt **nicht** für "Bulk"-Löschungen, die mit dem delete()-Konstrukt ausgegeben würden, wie unter ORM UPDATE und DELETE mit benutzerdefinierten WHERE-Kriterien beschrieben. Weitere Hintergrundinformationen finden Sie unter Wichtige Hinweise und Vorbehalte für ORM-fähige Update und Delete.
Siehe auch
Verwendung von foreign key ON DELETE cascade bei ORM-Beziehungen
Verwendung von Delete-Kaskaden bei Many-to-Many-Beziehungen¶
Die Option cascade="all, delete" funktioniert auch gut bei einer Many-to-Many-Beziehung, die relationship.secondary verwendet, um eine Assoziationstabelle anzugeben. Wenn ein Eltern-Objekt gelöscht und somit von seinen zugehörigen Objekten getrennt wird, löscht der Unit-of-Work-Prozess normalerweise Zeilen aus der Assoziationstabelle, lässt aber die zugehörigen Objekte intakt. In Kombination mit cascade="all, delete" werden zusätzliche DELETE-Anweisungen für die Kind-Zeilen selbst ausgeführt.
Das folgende Beispiel passt das von Viele zu Viele an, um die Einstellung cascade="all, delete" auf **einer** Seite der Assoziation zu veranschaulichen.
association_table = Table(
"association",
Base.metadata,
Column("left_id", Integer, ForeignKey("left.id")),
Column("right_id", Integer, ForeignKey("right.id")),
)
class Parent(Base):
__tablename__ = "left"
id = mapped_column(Integer, primary_key=True)
children = relationship(
"Child",
secondary=association_table,
back_populates="parents",
cascade="all, delete",
)
class Child(Base):
__tablename__ = "right"
id = mapped_column(Integer, primary_key=True)
parents = relationship(
"Parent",
secondary=association_table,
back_populates="children",
)Oben, wenn ein Parent-Objekt mit Session.delete() zum Löschen markiert wird, löscht der Flush-Prozess wie üblich die zugehörigen Zeilen aus der association-Tabelle. Gemäß den Kaskadenregeln werden jedoch auch alle zugehörigen Child-Zeilen gelöscht.
Warnung
Wenn die obige Einstellung cascade="all, delete" auf **beiden** Beziehungen konfiguriert wäre, würde die Kaskadenaktion durch alle Parent- und Child-Objekte weiterkaskadieren, jede children- und parents-Sammlung laden, die angetroffen wird, und alles löschen, was verbunden ist. Es ist typischerweise nicht wünschenswert, die "delete"-Kaskade bidirektional zu konfigurieren.
Verwendung von FOREIGN KEY ON DELETE CASCADE mit ORM-Beziehungen¶
Das Verhalten der "delete"-Kaskade von SQLAlchemy überschneidet sich mit der ON DELETE-Funktion einer FOREIGN KEY-Beschränkung der Datenbank. SQLAlchemy ermöglicht die Konfiguration dieser schema-bezogenen DDL-Verhaltensweisen mit den Konstrukten ForeignKey und ForeignKeyConstraint; die Verwendung dieser Objekte in Verbindung mit Metadaten von Table wird unter ON UPDATE und ON DELETE beschrieben.
Um ON DELETE Fremdschlüsselkaskaden in Verbindung mit relationship() zu verwenden, ist es in erster Linie wichtig zu beachten, dass die Einstellung relationship.cascade weiterhin so konfiguriert werden muss, dass sie dem gewünschten Verhalten "delete" oder "set null" entspricht (mit delete Kaskade oder wenn sie weggelassen wird), damit, ob die ORM oder die datenbankseitigen Beschränkungen die Aufgabe der tatsächlichen Datenänderung in der Datenbank übernehmen, die ORM den Zustand lokal vorhandener Objekte, die betroffen sein könnten, weiterhin ordnungsgemäß nachverfolgen kann.
Es gibt dann eine zusätzliche Option auf relationship(), die angibt, inwieweit die ORM versuchen soll, DELETE/UPDATE-Operationen auf zugehörigen Zeilen selbst auszuführen, im Gegensatz dazu, wie stark sie sich darauf verlassen soll, dass die datenbankseitige FOREIGN KEY-Beschränkung die Aufgabe übernimmt; dies ist der Parameter relationship.passive_deletes und er akzeptiert die Optionen False (Standard), True und "all".
Das typischste Beispiel ist, dass Kind-Zeilen gelöscht werden sollen, wenn Eltern-Zeilen gelöscht werden, und dass ON DELETE CASCADE auf der entsprechenden FOREIGN KEY-Beschränkung konfiguriert ist.
class Parent(Base):
__tablename__ = "parent"
id = mapped_column(Integer, primary_key=True)
children = relationship(
"Child",
back_populates="parent",
cascade="all, delete",
passive_deletes=True,
)
class Child(Base):
__tablename__ = "child"
id = mapped_column(Integer, primary_key=True)
parent_id = mapped_column(Integer, ForeignKey("parent.id", ondelete="CASCADE"))
parent = relationship("Parent", back_populates="children")Das Verhalten der obigen Konfiguration beim Löschen einer Eltern-Zeile ist wie folgt:
Die Anwendung ruft
session.delete(my_parent)auf, wobeimy_parenteine Instanz vonParentist.Wenn die
Sessionals nächstes Änderungen in die Datenbank weiterleitet, werden alle **aktuell geladenen** Elemente in der Sammlungmy_parent.childrenvon der ORM gelöscht, was bedeutet, dass für jeden Datensatz eineDELETE-Anweisung ausgegeben wird.Wenn die Sammlung
my_parent.children**entladen** ist, werden keineDELETE-Anweisungen ausgegeben. Wenn das Flagrelationship.passive_deletesauf dieserrelationship()**nicht** gesetzt wäre, wäre eineSELECT-Anweisung für entladeneChild-Objekte ausgegeben worden.Anschließend wird eine
DELETE-Anweisung für die Zeilemy_parentselbst ausgegeben.Die datenbankseitige Einstellung
ON DELETE CASCADEstellt sicher, dass alle Zeilen inchild, die auf die betroffene Zeile inparentverweisen, ebenfalls gelöscht werden.Die
Parent-Instanz, auf die sichmy_parentbezieht, sowie alleChild-Instanzen, die mit diesem Objekt verbunden waren und **geladen** wurden (d.h. Schritt 2 oben fand statt), werden von derSessiongetrennt.
Hinweis
Um "ON DELETE CASCADE" zu verwenden, muss die zugrunde liegende Datenbank-Engine FOREIGN KEY-Beschränkungen unterstützen und sie müssen erzwungen werden.
Bei Verwendung von MySQL muss eine geeignete Speicher-Engine ausgewählt werden. Details finden Sie unter CREATE TABLE Argumente einschließlich Speicher-Engines.
Bei Verwendung von SQLite muss die Unterstützung für Fremdschlüssel explizit aktiviert werden. Details finden Sie unter Fremdschlüsselunterstützung.
Verwendung von Fremdschlüssel ON DELETE mit vielen-zu-vielen-Beziehungen¶
Wie unter Verwendung der Delete-Kaskadierung mit vielen-zu-vielen-Beziehungen beschrieben, funktioniert die "delete"-Kaskadierung auch für viele-zu-viele-Beziehungen. Um ON DELETE CASCADE Fremdschlüssel in Verbindung mit vielen-zu-vielen zu nutzen, werden FOREIGN KEY Direktiven auf der Assoziationstabelle konfiguriert. Diese Direktiven können die Aufgabe des automatischen Löschens aus der Assoziationstabelle übernehmen, aber nicht die des automatischen Löschens der zugehörigen Objekte selbst.
In diesem Fall kann die relationship.passive_deletes Direktive uns einige zusätzliche SELECT Anweisungen während einer Löschoperation ersparen, aber es gibt immer noch einige Sammlungen, die das ORM weiterhin laden wird, um betroffene Kindobjekte zu lokalisieren und diese korrekt zu behandeln.
Hinweis
Hypothetische Optimierungen hierfür könnten eine einzelne DELETE Anweisung gegen alle Elter-assoziierten Zeilen der Assoziationstabelle auf einmal sein, dann RETURNING verwenden, um betroffene zugehörige Kindzeilen zu lokalisieren, dies ist jedoch derzeit nicht Teil der ORM Unit of Work Implementierung.
In dieser Konfiguration konfigurieren wir ON DELETE CASCADE auf beiden Fremdschlüsselbeschränkungen der Assoziationstabelle. Wir konfigurieren cascade="all, delete" auf der Eltern->Kind-Seite der Beziehung, und wir können dann passive_deletes=True auf der **anderen** Seite der bidirektionalen Beziehung konfigurieren, wie unten gezeigt.
association_table = Table(
"association",
Base.metadata,
Column("left_id", Integer, ForeignKey("left.id", ondelete="CASCADE")),
Column("right_id", Integer, ForeignKey("right.id", ondelete="CASCADE")),
)
class Parent(Base):
__tablename__ = "left"
id = mapped_column(Integer, primary_key=True)
children = relationship(
"Child",
secondary=association_table,
back_populates="parents",
cascade="all, delete",
)
class Child(Base):
__tablename__ = "right"
id = mapped_column(Integer, primary_key=True)
parents = relationship(
"Parent",
secondary=association_table,
back_populates="children",
passive_deletes=True,
)Mit der obigen Konfiguration erfolgt die Löschung eines Parent Objekts wie folgt:
Ein
ParentObjekt wird zur Löschung markiert, indemSession.delete()verwendet wird.Wenn der Flush auftritt, und die
Parent.childrenSammlung nicht geladen ist, gibt das ORM zuerst eine SELECT-Anweisung aus, um dieChildObjekte zu laden, dieParent.childrenentsprechen.Anschließend gibt es
DELETEAnweisungen für die Zeilen inassociationaus, die der Elternzeile entsprechen.Für jedes
ChildObjekt, das von dieser sofortigen Löschung betroffen ist, dapassive_deletes=Truekonfiguriert ist, muss die Unit of Work nicht versuchen, SELECT-Anweisungen für jedeChild.parentsSammlung auszugeben, da angenommen wird, dass die entsprechenden Zeilen inassociationgelöscht werden.DELETEAnweisungen werden dann für jedesChildObjekt ausgegeben, das ausParent.childrengeladen wurde.
delete-orphan¶
delete-orphan Kaskadierung fügt der delete Kaskadierung Verhalten hinzu, sodass ein Kindobjekt gelöscht wird, wenn es vom Elternteil getrennt wird, nicht nur, wenn der Elternteil zur Löschung markiert wird. Dies ist ein übliches Merkmal, wenn man mit einem zugehörigen Objekt umgeht, das von seinem Elternteil "besessen" wird, mit einem NOT NULL Fremdschlüssel, sodass die Entfernung des Elements aus der Elternsammlung dessen Löschung zur Folge hat.
delete-orphan Kaskadierung impliziert, dass jedes Kindobjekt zu einem Zeitpunkt nur einen Elternteil haben kann, und in den **allermeisten Fällen wird es nur auf einer Eins-zu-viele-Beziehung konfiguriert.** Für den weitaus selteneren Fall, es auf einer viele-zu-eins- oder viele-zu-viele-Beziehung zu setzen, kann die "viele"-Seite gezwungen werden, nur ein Objekt gleichzeitig zuzulassen, indem das Argument relationship.single_parent konfiguriert wird, welches eine Python-seitige Validierung etabliert, die sicherstellt, dass das Objekt zu einem Zeitpunkt nur mit einem Elternteil assoziiert ist, dies schränkt jedoch die Funktionalität der "vielen"-Beziehung stark ein und ist normalerweise nicht das, was gewünscht wird.
Siehe auch
Für Beziehung <relationship>, delete-orphan Kaskadierung ist normalerweise nur auf der "einen" Seite einer Eins-zu-viele-Beziehung konfiguriert und nicht auf der "vielen" Seite einer viele-zu-eins- oder viele-zu-viele-Beziehung. - Hintergrund zu einem häufigen Fehler-Szenario im Zusammenhang mit delete-orphan Kaskadierung.
merge¶
merge Kaskadierung zeigt an, dass die Session.merge() Operation vom Elternteil, der Gegenstand des Session.merge() Aufrufs auf zugehörige Objekte übertragen werden sollte. Diese Kaskadierung ist ebenfalls standardmäßig aktiviert.
refresh-expire¶
refresh-expire ist eine ungewöhnliche Option, die angibt, dass die Session.expire() Operation vom Elternteil auf zugehörige Objekte übertragen werden sollte. Bei Verwendung von Session.refresh() werden die zugehörigen Objekte nur abgelaufen, aber nicht tatsächlich aktualisiert.
expunge¶
expunge Kaskadierung zeigt an, dass, wenn das Elternobjekt mit Session.expunge() aus der Session entfernt wird, die Operation auf die zugehörigen Objekte übertragen werden soll.
Anmerkungen zu Delete - Löschen von Objekten, auf die aus Sammlungen und Skalaren Beziehungen verwiesen wird¶
Das ORM ändert im Allgemeinen niemals den Inhalt einer Sammlung oder einer Skalarbeziehung während des Flush-Prozesses. Das bedeutet, wenn Ihre Klasse eine relationship() hat, die auf eine Sammlung von Objekten verweist, oder eine Referenz auf ein einzelnes Objekt wie viele-zu-eins, wird der Inhalt dieses Attributs während des Flush-Prozesses nicht geändert. Stattdessen wird erwartet, dass die Session schließlich abgelaufen wird, entweder durch das expire-on-commit Verhalten von Session.commit() oder durch explizite Verwendung von Session.expire(). Zu diesem Zeitpunkt wird jedes referenzierte Objekt oder jede Sammlung, die mit dieser Session verbunden ist, gelöscht und wird sich beim nächsten Zugriff neu laden.
Eine häufige Verwirrung, die sich aus diesem Verhalten ergibt, betrifft die Verwendung der Methode Session.delete(). Wenn Session.delete() auf ein Objekt angewendet wird und die Session geflusht wird, wird die Zeile aus der Datenbank gelöscht. Zeilen, die über einen Fremdschlüssel auf die Zielzeile verweisen, werden, vorausgesetzt, sie werden mit einer relationship() zwischen den beiden abgebildeten Objekttypen verfolgt, ebenfalls ihre Fremdschlüsselattribute auf null AKTUALISIERT sehen, oder wenn eine Löschkaskade eingerichtet ist, werden die zugehörigen Zeilen ebenfalls gelöscht. Aber selbst wenn Zeilen, die mit dem gelöschten Objekt in Beziehung stehen, selbst modifiziert werden, **erfolgen keine Änderungen an beziehungsgebundenen Sammlungen oder Objektverweisen auf den beteiligten Objekten** im Rahmen des Flushs selbst. Das bedeutet, wenn das Objekt Mitglied einer zugehörigen Sammlung war, wird es auf der Python-Seite noch vorhanden sein, bis diese Sammlung abgelaufen ist. Ebenso, wenn das Objekt über viele-zu-eins oder eins-zu-eins von einem anderen Objekt referenziert wurde, wird diese Referenz auf diesem Objekt verbleiben, bis das Objekt ebenfalls abgelaufen ist.
Unten illustrieren wir, dass, nachdem ein Address Objekt zur Löschung markiert wurde, es immer noch in der Sammlung vorhanden ist, die mit dem übergeordneten User verbunden ist, selbst nach einem Flush.
>>> address = user.addresses[1]
>>> session.delete(address)
>>> session.flush()
>>> address in user.addresses
TrueWenn die obige Sitzung committed wird, sind alle Attribute abgelaufen. Der nächste Zugriff auf user.addresses wird die Sammlung neu laden und den gewünschten Zustand offenbaren.
>>> session.commit()
>>> address in user.addresses
FalseEs gibt ein Rezept, um Session.delete() abzufangen und dieses Ablaufen automatisch aufzurufen; siehe ExpireRelationshipOnFKChange hierfür. Die übliche Praxis des Löschens von Elementen innerhalb von Sammlungen besteht jedoch darin, die Verwendung von Session.delete() direkt zu vermeiden und stattdessen Kaskadenverhalten zu verwenden, um die Löschung automatisch als Ergebnis der Entfernung des Objekts aus der Elternsammlung aufzurufen. Die delete-orphan Kaskadierung erreicht dies, wie im folgenden Beispiel illustriert.
class User(Base):
__tablename__ = "user"
# ...
addresses = relationship("Address", cascade="all, delete-orphan")
# ...
del user.addresses[1]
session.flush()Wo oben, bei der Entfernung des Address Objekts aus der User.addresses Sammlung, hat die delete-orphan Kaskadierung den Effekt, dass das Address Objekt zur Löschung markiert wird, genauso wie wenn es an Session.delete() übergeben würde.
Die delete-orphan Kaskadierung kann auch auf eine viele-zu-eins- oder eins-zu-eins-Beziehung angewendet werden, so dass, wenn ein Objekt von seinem Elternteil getrennt wird, es ebenfalls automatisch zur Löschung markiert wird. Die Verwendung der delete-orphan Kaskadierung auf eine viele-zu-eins- oder eins-zu-eins-Beziehung erfordert ein zusätzliches Flag relationship.single_parent, welches eine Assertion auslöst, dass dieses zugehörige Objekt nicht gleichzeitig mit einem anderen Elternteil geteilt wird.
class User(Base):
# ...
preference = relationship(
"Preference", cascade="all, delete-orphan", single_parent=True
)Oben, wenn ein hypothetisches Preference Objekt von einem User entfernt wird, wird es beim Flush gelöscht.
some_user.preference = None
session.flush() # will delete the Preference objectSiehe auch
Kaskadierung für Details zu Kaskadierungen.
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