SQLAlchemy Relationships (One-to-Many, Many-to-Many)
Introduction
In real-world applications, tables are connected, not isolated.
Examples:
- A user can have many orders
- A student can enroll in many courses
- A product can belong to multiple categories
These connections are called relationships in SQLAlchemy.
Types of Relationships
| Type | Example |
|---|---|
| One-to-One | User ↔ Profile |
| One-to-Many | User → Orders |
| Many-to-Many | Students ↔ Courses |
1. One-to-Many Relationship
Scenario :One User can have multiple Orders
Step 1: Define Models
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import declarative_base, relationship
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String)
orders = relationship("Order", back_populates="user")
class Order(Base):
__tablename__ = "orders"
id = Column(Integer, primary_key=True)
amount = Column(Integer)
user_id = Column(Integer, ForeignKey("users.id"))
user = relationship("User", back_populates="orders")
Key Concepts
-
ForeignKey→ Creates link between tables -
relationship()→ Enables ORM-level connection -
back_populates→ Two-way relationship
Example Usage
# Create useruser = User(name="John")# Create ordersorder1 = Order(amount=500)order2 = Order(amount=1000)# Link orders to useruser.orders = [order1, order2]session.add(user)session.commit()Access Related Data
# Get user's ordersuser = session.query(User).first()print(user.orders)# Get order's userorder = session.query(Order).first()print(order.user.name)Real-World Tip
Use
lazy="select"(default) or optimize with eager loading (covered below).
2. Many-to-Many Relationship
Scenario :A Student can enroll in multiple Courses .A Course can have multiple Students.
Step 1: Association Table
from sqlalchemy import Tablestudent_course = Table("student_course",Base.metadata,Column("student_id", ForeignKey("students.id"), primary_key=True),Column("course_id", ForeignKey("courses.id"), primary_key=True))Step 2: Define Models
class Student(Base):__tablename__ = "students"id = Column(Integer, primary_key=True)name = Column(String)courses = relationship("Course", secondary=student_course, back_populates="students")class Course(Base):__tablename__ = "courses"id = Column(Integer, primary_key=True)title = Column(String)students = relationship("Student", secondary=student_course, back_populates="courses")Example Usage
student = Student(name="Alice")course1 = Course(title="Python")course2 = Course(title="SQL")student.courses = [course1, course2]session.add(student)session.commit()Access Data
student = session.query(Student).first()print(student.courses)course = session.query(Course).first()print(course.students)3. One-to-One Relationship
Scenario :One User has one Profile
Implementationclass User(Base):__tablename__ = "users"id = Column(Integer, primary_key=True)name = Column(String)profile = relationship("Profile", uselist=False, back_populates="user")class Profile(Base): __tablename__ = "profiles" id = Column(Integer, primary_key=True) bio = Column(String) user_id = Column(Integer, ForeignKey("users.id"))user = relationship("User", back_populates="profile")Key Point :
uselist=Falsemakes it one-to-one4.Cascade Operations
What is Cascade?
Automatically apply actions (delete, update) to related records
Example
orders = relationship("Order", cascade="all, delete")If user is deleted → orders also deleted
5. Lazy vs Eager Loading
Lazy Loading (Default)
user = session.query(User).first()print(user.orders) # triggers queryEager Loading (Optimized)
from sqlalchemy.orm import joinedloaduser = session.query(User).options(joinedload(User.orders)).first()Loads data in single query
6. Backref (Shortcut)
Instead of
back_populates, you can use:from sqlalchemy.orm import backreforders = relationship("Order", backref="user")
Real-World Example (E-Commerce)
- User → Orders (One-to-Many)
- Product ↔ Category (Many-to-Many)
- User → Profile (One-to-One)
Common Mistakes
- Forgetting
ForeignKey- Missing
back_populates- Not handling cascade deletes
- Ignoring performance (N+1 problem)
Comments
Post a Comment