Many to Many Relationships
- id: 1749652195
- Date: June 11, 2025, 2:30 p.m.
- Author: Donald F. Elger
Goals
- Describe many-to-many relationships.
- Explain how to create M:M relationships in Django.
- Skillfully use M:M relationships: add, upsert, query, and such.
Many-to-Many Relationships
What Is a Many-to-Many Relationship?
A many-to-many (M:M) relationship means that:
- One item from Model A can be linked to many items from Model B.
- One item from Model B can also be linked to many items from Model A.
Examples: - A student can take multiple courses. A course can have multiple students. - A tag can apply to multiple blog posts. A blog post can have multiple tags.
Creating Many-to-Many Relationships in Django
Option 1: Simple M:M
with ManyToManyField
from django.db import models
class Student(models.Model):
= models.CharField(max_length=100)
name
class Course(models.Model):
= models.CharField(max_length=100)
title = models.ManyToManyField(Student) students
This automatically creates a hidden join table behind the scenes.
Option 2: Explicit Through Table for Custom Fields
Use this if you need to store extra information about the relationship.
from django.db import models
class Student(models.Model):
= models.CharField(max_length=100)
name
class Course(models.Model):
= models.CharField(max_length=100)
title = models.ManyToManyField('Student', through='Enrollment')
students
class Enrollment(models.Model):
= models.ForeignKey('Student', on_delete=models.CASCADE)
student = models.ForeignKey('Course', on_delete=models.CASCADE)
course = models.DateField() enrollment_date
Using Many-to-Many Relationships
Add a Relationship
Simple M:M:
student = Student.objects.get(id=1)
course = Course.objects.get(id=2)
course.students.add(student)
With a Through Table:
Enrollment.objects.create(
student=student,
course=course,
enrollment_date="2025-06-11"
)
Upsert (Update if exists, otherwise insert)
enrollment, created = Enrollment.objects.update_or_create(
student=student,
course=course,
defaults={'enrollment_date': '2025-06-11'}
)
Query Relationships
Simple M:M:
# Get all students in a course
course.students.all()
# Get all courses a student is in
student.course_set.all() # reverse lookup using default naming
With Through Table:
# Get all enrollments for a student
Enrollment.objects.filter(student=student)
# Get all courses for a student through enrollment
Course.objects.filter(enrollment__student=student)
Remove or Clear Relationships
# Remove one student from a course (simple M:M only)
course.students.remove(student)
# Remove all students from a course
course.students.clear()
Customize Reverse Access
You can customize the reverse access name:
students = models.ManyToManyField(Student, related_name='enrolled_courses')
Then you can access:
student.enrolled_courses.all()
Migrations
After defining or updating your models:
python manage.py makemigrations
python manage.py migrate
Summary
- Use ManyToManyField for simple many-to-many links.
- Use a through= table when you need extra fields on the relationship.
- Manage links using .add(), .remove(), .clear(), and .update_or_create().
- Query relationships from both sides using forward and reverse accessors.
- Customize reverse access with related_name if desired.