SQLAlchemy ORM - Xóa các đối tượng liên quan

Dễ dàng thực hiện thao tác xóa trên một bảng. Tất cả những gì bạn phải làm là xóa một đối tượng của lớp được ánh xạ khỏi một phiên và thực hiện hành động. Tuy nhiên, thao tác xóa trên nhiều bảng liên quan hơi phức tạp.

Trong cơ sở dữ liệu sales.db của chúng tôi, các lớp Khách hàng và Hóa đơn được ánh xạ tới bảng khách hàng và hóa đơn với kiểu quan hệ từ một đến nhiều. Chúng tôi sẽ thử xóa đối tượng Khách hàng và xem kết quả.

Để tham khảo nhanh, dưới đây là định nghĩa của các lớp Khách hàng và Hóa đơn -

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")

Chúng tôi thiết lập một phiên và lấy đối tượng Khách hàng bằng cách truy vấn nó với ID chính bằng chương trình bên dưới:

from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()
x = session.query(Customer).get(2)

Trong bảng mẫu của chúng tôi, x.name tình cờ là 'Gopal Krishna'. Hãy để chúng tôi xóa x này khỏi phiên và đếm sự xuất hiện của tên này.

session.delete(x)
session.query(Customer).filter_by(name = 'Gopal Krishna').count()

Biểu thức SQL kết quả sẽ trả về 0.

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

Tuy nhiên, các đối tượng Invoice liên quan của x vẫn còn đó. Nó có thể được xác minh bằng mã sau:

session.query(Invoice).filter(Invoice.invno.in_([10,14])).count()

Ở đây, 10 và 14 là số hóa đơn thuộc về khách hàng Gopal Krishna. Kết quả của truy vấn trên là 2, có nghĩa là các đối tượng liên quan chưa bị xóa.

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

Điều này là do SQLAlchemy không giả định việc xóa thác; chúng ta phải đưa ra một lệnh để xóa nó.

Để thay đổi hành vi, chúng tôi định cấu hình các tùy chọn tầng trên mối quan hệ User.addresses. Hãy để chúng tôi đóng phiên đang diễn ra, sử dụng new secure_base () và khai báo lại lớp Người dùng, thêm vào mối quan hệ địa chỉ bao gồm cả cấu hình tầng.

Thuộc tính cascade trong hàm mối quan hệ là một danh sách được phân tách bằng dấu phẩy các quy tắc xếp tầng xác định cách các hoạt động của Session nên được “xếp tầng” từ cha sang con. Theo mặc định, nó là False, có nghĩa là nó là "save-update, merge".

Các tầng có sẵn như sau:

  • save-update
  • merge
  • expunge
  • delete
  • delete-orphan
  • refresh-expire

Tùy chọn thường được sử dụng là "all, delete-orphan" để chỉ ra rằng các đối tượng liên quan sẽ theo sau cùng với đối tượng mẹ trong mọi trường hợp và bị xóa khi hủy liên kết.

Do đó, lớp Khách hàng được khai báo lại được hiển thị bên dưới:

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" 
   )

Hãy để chúng tôi xóa Khách hàng có tên Gopal Krishna bằng chương trình bên dưới và xem số lượng các đối tượng Hóa đơn có liên quan của nó -

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()

Số lượng bây giờ là 0 với SQL sau được phát ra bởi tập lệnh trên:

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