SQLAlchemy Core
- Using Set Operations
- Using Functions
- Using Conjunctions
- Using Joins
- Multiple Table Deletes
- Parameter-Ordered Updates
- Using Multiple Table Updates
- Using Multiple Tables
- Using DELETE Expression
- Using UPDATE Expression
- Using Aliases
- Using Textual SQL
- Selecting Rows
- Executing Expression
- SQL Expressions
- Creating Table
- Connecting to Database
- Expression Language
SQLAlchemy ORM
- Dialects
- Many to Many Relationships
- Deleting Related Objects
- Eager Loading
- Common Relationship Operators
- Working with Joins
- Working with Related Objects
- Building Relationship
- Textual SQL
- Returning List and Scalars
- Filter Operators
- Applying Filter
- Updating Objects
- Using Query
- Adding Objects
- Creating Session
- Declaring Mapping
SQLAlchemy Useful Resources
Selected Reading
- Who is Who
- Computer Glossary
- HR Interview Questions
- Effective Resume Writing
- Questions and Answers
- UPSC IAS Exams Notes
SQLAlchemy ORM - Deleting Related Objects
It is easy to perform delete operation on a single table. All you have to do is to delete an object of the mapped class from a session and commit the action. However, delete operation on multiple related tables is pttle tricky.
In our sales.db database, Customer and Invoice classes are mapped to customer and invoice table with one to many type of relationship. We will try to delete Customer object and see the result.
As a quick reference, below are the definitions of Customer and Invoice classes −
from sqlalchemy import create_engine, ForeignKey, Column, Integer, String engine = create_engine( sqpte:///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")
We setup a session and obtain a Customer object by querying it with primary ID using the below program −
from sqlalchemy.orm import sessionmaker Session = sessionmaker(bind=engine) session = Session() x = session.query(Customer).get(2)
In our sample table, x.name happens to be Gopal Krishna . Let us delete this x from the session and count the occurrence of this name.
session.delete(x) session.query(Customer).filter_by(name = Gopal Krishna ).count()
The resulting SQL expression will return 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
However, the related Invoice objects of x are still there. It can be verified by the following code −
session.query(Invoice).filter(Invoice.invno.in_([10,14])).count()
Here, 10 and 14 are invoice numbers belonging to customer Gopal Krishna. Result of the above query is 2, which means the related objects have not been deleted.
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
This is because SQLAlchemy doesn’t assume the deletion of cascade; we have to give a command to delete it.
To change the behavior, we configure cascade options on the User.addresses relationship. Let us close the ongoing session, use new declarative_base() and redeclare the User class, adding in the addresses relationship including the cascade configuration.
The cascade attribute in relationship function is a comma-separated pst of cascade rules which determines how Session operations should be “cascaded” from parent to child. By default, it is False, which means that it is "save-update, merge".
The available cascades are as follows −
save-update
merge
expunge
delete
delete-orphan
refresh-expire
Often used option is "all, delete-orphan" to indicate that related objects should follow along with the parent object in all cases, and be deleted when de-associated.
Hence redeclared Customer class is shown below −
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" )
Let us delete the Customer with Gopal Krishna name using the below program and see the count of its related Invoice objects −
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()
The count is now 0 with following SQL emitted by above script −
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) 0Advertisements