SQLAlchemy ORM - Löschen verwandter Objekte
Es ist einfach, einen Löschvorgang für eine einzelne Tabelle durchzuführen. Sie müssen lediglich ein Objekt der zugeordneten Klasse aus einer Sitzung löschen und die Aktion festschreiben. Das Löschen mehrerer verwandter Tabellen ist jedoch wenig schwierig.
In unserer sales.db-Datenbank werden Kunden- und Rechnungsklassen Kunden- und Rechnungstabellen mit einer bis mehreren Arten von Beziehungen zugeordnet. Wir werden versuchen, das Kundenobjekt zu löschen und das Ergebnis zu sehen.
Im Folgenden finden Sie als Kurzreferenz die Definitionen der Kunden- und Rechnungsklassen.
from sqlalchemy import create_engine, ForeignKey, Column, Integer, String
engine = create_engine('sqlite:///sales.db', echo = True)
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
from sqlalchemy.orm import relationship
class Customer(Base):
__tablename__ = 'customers'
id = Column(Integer, primary_key = True)
name = Column(String)
address = Column(String)
email = Column(String)
class Invoice(Base):
__tablename__ = 'invoices'
id = Column(Integer, primary_key = True)
custid = Column(Integer, ForeignKey('customers.id'))
invno = Column(Integer)
amount = Column(Integer)
customer = relationship("Customer", back_populates = "invoices")
Customer.invoices = relationship("Invoice", order_by = Invoice.id, back_populates = "customer")
Wir richten eine Sitzung ein und erhalten ein Kundenobjekt, indem wir es mit der primären ID mit dem folgenden Programm abfragen.
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()
x = session.query(Customer).get(2)
In unserer Beispieltabelle ist x.name zufällig 'Gopal Krishna'. Löschen wir dieses x aus der Sitzung und zählen das Auftreten dieses Namens.
session.delete(x)
session.query(Customer).filter_by(name = 'Gopal Krishna').count()
Der resultierende SQL-Ausdruck gibt 0 zurück.
SELECT count(*)
AS count_1
FROM (
SELECT customers.id
AS customers_id, customers.name
AS customers_name, customers.address
AS customers_address, customers.email
AS customers_email
FROM customers
WHERE customers.name = ?)
AS anon_1('Gopal Krishna',) 0
Die zugehörigen Rechnungsobjekte von x sind jedoch noch vorhanden. Es kann durch den folgenden Code überprüft werden -
session.query(Invoice).filter(Invoice.invno.in_([10,14])).count()
Hier sind 10 und 14 Rechnungsnummern des Kunden Gopal Krishna. Das Ergebnis der obigen Abfrage ist 2, was bedeutet, dass die zugehörigen Objekte nicht gelöscht wurden.
SELECT count(*)
AS count_1
FROM (
SELECT invoices.id
AS invoices_id, invoices.custid
AS invoices_custid, invoices.invno
AS invoices_invno, invoices.amount
AS invoices_amount
FROM invoices
WHERE invoices.invno IN (?, ?))
AS anon_1(10, 14) 2
Dies liegt daran, dass SQLAlchemy nicht das Löschen der Kaskade voraussetzt. Wir müssen einen Befehl geben, um es zu löschen.
Um das Verhalten zu ändern, konfigurieren wir Kaskadenoptionen für die Beziehung User.addresses. Lassen Sie uns die laufende Sitzung schließen, new declative_base () verwenden und die User-Klasse neu deklarieren und die Adressbeziehung einschließlich der Kaskadenkonfiguration hinzufügen.
Das Kaskadenattribut in der Beziehungsfunktion ist eine durch Kommas getrennte Liste von Kaskadenregeln, die bestimmt, wie Sitzungsoperationen von übergeordnet zu untergeordnet „kaskadiert“ werden sollen. Standardmäßig ist es False, was bedeutet, dass es "Update speichern, zusammenführen" ist.
Die verfügbaren Kaskaden sind wie folgt:
- save-update
- merge
- expunge
- delete
- delete-orphan
- refresh-expire
Die häufig verwendete Option ist "all, delete-orphan", um anzugeben, dass verwandte Objekte in allen Fällen zusammen mit dem übergeordneten Objekt folgen und gelöscht werden sollen, wenn die Zuordnung aufgehoben wird.
Daher wird die neu deklarierte Kundenklasse unten angezeigt -
class Customer(Base):
__tablename__ = 'customers'
id = Column(Integer, primary_key = True)
name = Column(String)
address = Column(String)
email = Column(String)
invoices = relationship(
"Invoice",
order_by = Invoice.id,
back_populates = "customer",
cascade = "all,
delete, delete-orphan"
)
Lassen Sie uns den Kunden mit dem Namen Gopal Krishna mit dem folgenden Programm löschen und die Anzahl der zugehörigen Rechnungsobjekte anzeigen.
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind = engine)
session = Session()
x = session.query(Customer).get(2)
session.delete(x)
session.query(Customer).filter_by(name = 'Gopal Krishna').count()
session.query(Invoice).filter(Invoice.invno.in_([10,14])).count()
Die Anzahl ist jetzt 0 mit folgendem SQL, das vom obigen Skript ausgegeben wird -
SELECT customers.id
AS customers_id, customers.name
AS customers_name, customers.address
AS customers_address, customers.email
AS customers_email
FROM customers
WHERE customers.id = ?
(2,)
SELECT invoices.id
AS invoices_id, invoices.custid
AS invoices_custid, invoices.invno
AS invoices_invno, invoices.amount
AS invoices_amount
FROM invoices
WHERE ? = invoices.custid
ORDER BY invoices.id (2,)
DELETE FROM invoices
WHERE invoices.id = ? ((1,), (2,))
DELETE FROM customers
WHERE customers.id = ? (2,)
SELECT count(*)
AS count_1
FROM (
SELECT customers.id
AS customers_id, customers.name
AS customers_name, customers.address
AS customers_address, customers.email
AS customers_email
FROM customers
WHERE customers.name = ?)
AS anon_1('Gopal Krishna',)
SELECT count(*)
AS count_1
FROM (
SELECT invoices.id
AS invoices_id, invoices.custid
AS invoices_custid, invoices.invno
AS invoices_invno, invoices.amount
AS invoices_amount
FROM invoices
WHERE invoices.invno IN (?, ?))
AS anon_1(10, 14)
0