Sling Academy
Home/SQLAlchemy/SQLAlchemy: How to Use Many-To-Many Relationships

SQLAlchemy: How to Use Many-To-Many Relationships

Last updated: January 04, 2024

Overview

Understanding many-to-many relationships in SQLAlchemy is crucial for building complex models in Python-based web applications.

Introduction to Many-To-Many

Many-to-many relationships occur when a single record in a table is associated with multiple records in another table, and vice versa. For instance, in a basic model of students and courses, a single student can enroll in many courses, and each course can be taken by multiple students. To represent this in a database, an association table is often used, creating a two-way link between the tables that represent each entity.

In SQLAlchemy, which is the Python SQL Toolkit and Object Relational Mapper (ORM), a many-to-many relationship is implemented using the relationship() function in combination with Table constructs to define the association table, and secondary keyword argument to define the association table that helps map the relations.

from sqlalchemy import Table, Column, Integer, ForeignKey, create_engine
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()
engine = create_engine('sqlite:///:memory:')

association_table = Table('association', Base.metadata,
  Column('left_id', Integer, ForeignKey('left.id')),
  Column('right_id', Integer, ForeignKey('right.id'))
)

class Left(Base):
  __tablename__ = 'left'
  id = Column(Integer, primary_key=True)
  rights = relationship('Right', secondary=association_table)

class Right(Base):
  __tablename__ = 'right'
  id = Column(Integer, primary_key=True)

Defining the Models

To dive deeper into implementing many-to-many relationships with SQLAlchemy, let’s establish two entity models: Student and Course.

class Student(Base):
  __tablename__ = 'student'
  id = Column(Integer, primary_key=True)
  name = Column(String)

class Course(Base):
  __tablename__ = 'course'
  id = Column(Integer, primary_key=True)
  name = Column(String)
  students = relationship('Student', secondary=association_table)

Setting Up the Association Table

The association table resembles a standard table in SQLAlchemy but typically includes two foreign key columns that reference the primary keys of the tables that we are linking together. This helps to set up a many-to-many database schema.

students_courses_association = Table('students_courses_association', Base.metadata,
  Column('student_id', Integer, ForeignKey('student.id')),
  Column('course_id', Integer, ForeignKey('course.id'))
)

Working with the ORM

After defining your models and the association table, you can begin working with the ORM to add records and query the many-to-many relationship.

Inserting Records

To insert data into these tables, you must first create instances of your models, then establish the connections by appending instances to the relationship property.

from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()

# Insert students
alice = Student(name='Alice')
bob = Student(name='Bob')
session.add_all([alice, bob])
session.commit()

# Insert courses
math = Course(name='Mathematics')
physics = Course(name='Physics')
session.add_all([math, physics])
session.commit()

Creating Associations

Associations can be created by adding instances of one model to the relationship property of instances of the other model.

alice.courses.append(math)
bob.courses.extend([math, physics])
session.commit()

Querying the Relationship

To query the relationships, you can use the ORM’s querying capabilities to load instances of one class that are related to instances of another.

for student in session.query(Student).join(Course, Student.courses).filter(Course.name == 'Mathematics'):
  print(student.name)

Conclusion

SQLAlchemy’s ORM allows for building complex database models with Python using idiomatical expressions that mirror the underlying SQL. By mastering many-to-many relationships, you are equipped to handle multifaceted data structures and create robust, data-driven applications using SQLAlchemy.

Next Article: SQLAlchemy: Delete Related Objects with Cascade

Previous Article: Exploring One-to-Many Relationships in SQLAlchemy

Series: SQLAlchemy Tutorials: From Basic to Advanced

SQLAlchemy

You May Also Like

  • SQLAlchemy: Counting rows for each category (2 approaches)
  • SQLAlchemy: Adding a calculated column to SELECT query
  • SQLAlchemy: Grouping data on multiple columns
  • SQLAlchemy: How to temporarily delete a row
  • SQLAlchemy Composite Indexes: The Complete Guide
  • Full-Text Search in SQLAlchemy: The Ultimate Guide
  • SQLAlchemy: What if you don’t close database connections?
  • SQLAlchemy: How to Remove FOREIGN KEY Constraints (2 Ways)
  • SQLAlchemy: How to Create and Use Temporary Tables
  • SQLAlchemy: Saving Categories and Subcategories in the Same Table
  • SQLAlchemy: How to Automatically Delete Old Records
  • Weighted Random Selection in SQLAlchemy: An In-Depth Guide
  • SQLAlchemy: created_at and updated_at columns
  • How to Use Regular Expressions in SQLAlchemy
  • SQLAlchemy: Ways to Find Results by a Keyword
  • SQLAlchemy: How to Connect to MySQL Database
  • SQLAlchemy: How to Bulk Insert Data into a Table
  • SQLAlchemy: How to Update a Record by ID
  • SQLAlchemy: Singular vs Plural Table Names