Exploring One-to-Many Relationships in SQLAlchemy

Updated: January 3, 2024 By: Guest Contributor Post a comment

Introduction

When working with databases in Python, understanding relationships between tables is crucial. SQLAlchemy, as an Object-Relational Mapping library, excels at managing these relationships. In this tutorial, we’ll delve into how to establish and work with one-to-many relationships using this powerful tool.

Understanding One-to-Many

One-to-many relationships occur when a single record in one table is associated with multiple records in another. In SQLAlchemy, this is typically represented through a ‘Parent’ and ‘Children’ model, where the parent record can have multiple children, but each child points back to only one parent.

from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import declarative_base, relationship, sessionmaker

Base = declarative_base()

class Parent(Base):
    __tablename__ = 'parents'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    # establish the one-to-many relation here
    children = relationship('Child', back_populates='parent')

class Child(Base):
    __tablename__ = 'children'
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('parents.id'))
    name = Column(String)
    # establish the inverse relationship here
    parent = relationship('Parent', back_populates='children')

# Creating a new SQLite database
engine = create_engine('sqlite:///mydatabase.db')
Base.metadata.create_all(engine)

# Creating a session to the database
Session = sessionmaker(bind=engine)
session = Session()

Adding Records

Once we’ve defined our models and relationships, we can add records that reflect this relationship. We’ll start by creating a parent and several child objects, then persisting them to the database.

# Adding a parent
parent = Parent(name='Parent 1')
session.add(parent)

# Adding children to the parent
parent.children = [Child(name='Child 1'), Child(name='Child 2')]
session.commit()

Querying

Retrieving data that reflects our one-to-many relationship is straightforward. We can query the parents and, thanks to the relationship we’ve established, access the children with ease.

our_parent = session.query(Parent).filter_by(name='Parent 1').first()
print(our_parent.children)  # Outputs the list of Child objects related to 'Parent 1'

Advanced Relationship Patterns

Beyond the basics, we might need to deal with scenarios like cascading deletes, lazy loading options, polymorphic relationships, etc. Here’s how to set up cascading deletes to ensure that when a parent is removed, all its children are too.

# Modifying the 'children' relationship with cascade options
Parent.children = relationship('Child', back_populates='parent', cascade='all, delete')

This ensures that deleting a Parent object automatically deletes its related Child objects:

# Delete a parent and its children
parent_to_delete = session.query(Parent).get(1)
session.delete(parent_to_delete)
session.commit()

Conclusion

Exploring and implementing one-to-many relationships in SQLAlchemy helps to build a strong foundation for any database-driven application. By understanding the basics and applying advanced patterns, developers can manage complex data models efficiently and effectively.