Lesson 40 of 60 – Django ManyToManyField
67%

Django ManyToManyField

The ManyToManyField is used when multiple objects from one model can be related to multiple objects from another model.

For example, a student can enroll in multiple courses, and each course can have multiple students.

Note: ManyToManyField is useful for many-to-many relationships such as students and courses, products and categories, or articles and tags.

1. What is ManyToManyField?

ManyToManyField creates a many-to-many relationship between two Django models.

For example:

Students ←→ Courses

A student can select many courses, and a course can contain many students.

2. Why Use ManyToManyField?

ManyToManyField is useful when both sides of a relationship can contain multiple related records.

  • Connect multiple objects together.
  • Avoid duplicate relationship data.
  • Represent real-world many-to-many relationships.
  • Make related queries easier.
  • Manage multiple connections through Django ORM.

3. Basic ManyToManyField Syntax

The basic syntax is:

field_name = models.ManyToManyField(
    ModelName
)

The field is normally defined on one of the models participating in the relationship.

4. Creating a Course Model

Suppose we have a Course model:

from django.db import models

class Course(models.Model):

    name = models.CharField(
        max_length=100
    )

    fee = models.IntegerField()

    def __str__(self):
        return self.name

This model stores course information.

5. Creating a Student Model

Now we can connect Student with Course using ManyToManyField.

class Student(models.Model):

    name = models.CharField(
        max_length=100
    )

    courses = models.ManyToManyField(
        Course
    )

A Student can now be connected with multiple Course objects.

6. Understanding Many-to-Many Relationship

Suppose three students are enrolled in different courses:

Rahul  → Python, SQL
Aman   → Java, Python
Priya  → SQL, Java

At the same time, Python can have Rahul and Aman, while SQL can have Rahul and Priya.

7. Django Creates an Intermediate Table

Django automatically manages an intermediate database table for a ManyToManyField.

Student
   ↓
Intermediate Relationship Table
   ↓
Course

You normally do not need to manually create this table when using the standard ManyToManyField configuration.

8. Creating a Student Object

First create a Student object:

student = Student.objects.create(
    name="Rahul"
)

The student can now be connected to one or more courses.

9. Creating Course Objects

python = Course.objects.create(
    name="Python",
    fee=10000
)

sql = Course.objects.create(
    name="SQL",
    fee=7000
)

Now we have two Course objects that can be assigned to the Student.

10. Adding One Course

Use the add() method to connect a Course to a Student.

student.courses.add(
    python
)

The Student is now connected to the Python course.

11. Adding Multiple Courses

Multiple courses can be added at the same time.

student.courses.add(
    python,
    sql
)

The student is now connected to both Python and SQL.

12. Reading Related Courses

Use all() to retrieve all courses associated with a student.

courses = student.courses.all()

for course in courses:

    print(course.name)

The result is a QuerySet containing related Course objects.

13. Checking Whether a Relationship Exists

The exists() method can be used to check whether related records exist.

if student.courses.exists():

    print("Courses found")

This is useful when you only need to know whether at least one related record exists.

14. Counting Related Courses

Use count() to find how many courses are associated with a student.

total = student.courses.count()

print(total)

This returns the number of related Course records.

15. Removing a Course

The remove() method removes a relationship between two objects.

student.courses.remove(
    python
)

The Python Course itself is not deleted. Only the relationship is removed.

16. Clearing All Relationships

The clear() method removes all Course relationships from a Student.

student.courses.clear()

The Course records remain in the database. Only the many-to-many connections are removed.

17. Using set()

The set() method replaces the current related objects with a new collection.

student.courses.set(
    [python, sql]
)

The student's existing Course relationships are replaced by the specified courses.

18. Using Through Table Automatically

Django creates and manages the intermediate relationship table automatically for a normal ManyToManyField.

class Student(models.Model):

    name = models.CharField(
        max_length=100
    )

    courses = models.ManyToManyField(
        Course
    )

You can work with the relationship through the Django ORM without manually managing the intermediate table.

19. Using related_name

The related_name option can customize the reverse relationship.

courses = models.ManyToManyField(
    Course,
    related_name="students"
)

Now a Course can access its related students using:

course.students.all()

20. Reverse Many-to-Many Relationship

If no related_name is specified, Django creates a default reverse relationship based on the model and field configuration.

With related_name="students", you can write:

students = course.students.all()

for student in students:

    print(student.name)

This allows you to move from Course back to Student.

21. Filtering Through ManyToManyField

Django allows you to filter Students using fields from related Courses.

students = Student.objects.filter(
    courses__name="Python"
)

The double underscore is used to traverse the many-to-many relationship.

22. Filtering Courses by Student

You can also find Courses associated with a particular Student.

courses = Course.objects.filter(
    students__name="Rahul"
)

This works when the reverse relationship is named students.

23. ManyToManyField in Templates

Related courses can be displayed in a Django template using a loop.

<h3>{{ student.name }}</h3>

<ul>

{% for course in student.courses.all %}

    <li>
        {{ course.name }}
    </li>

{% endfor %}

</ul>

The template can access all related Course objects.

24. ManyToManyField in a View

A view can retrieve a Student and pass it to a template.

from django.shortcuts import render
from .models import Student

def student_detail(request, id):

    student = Student.objects.get(
        id=id
    )

    return render(
        request,
        "student_detail.html",
        {"student": student}
    )

The template can then display the student's courses.

25. prefetch_related()

prefetch_related() can efficiently retrieve many-to-many relationships.

students = Student.objects.prefetch_related(
    "courses"
).all()

This can reduce unnecessary database queries when displaying many students and their related courses.

26. ManyToManyField with ModelForm

A ModelForm can include a ManyToManyField.

from django import forms
from .models import Student

class StudentForm(forms.ModelForm):

    class Meta:
        model = Student

        fields = [
            "name",
            "courses"
        ]

Django can provide a form control for selecting multiple related courses.

27. Custom Intermediate Model

Sometimes the relationship itself needs additional information. In that situation, Django allows you to define a custom intermediate model using through.

class Enrollment(models.Model):

    student = models.ForeignKey(
        Student,
        on_delete=models.CASCADE
    )

    course = models.ForeignKey(
        Course,
        on_delete=models.CASCADE
    )

    enrolled_date = models.DateField()

A custom intermediate model is useful when the relationship needs fields such as enrollment date, status, marks, or other information.

28. Complete ManyToManyField Example

from django.db import models


class Course(models.Model):

    name = models.CharField(
        max_length=100
    )

    fee = models.IntegerField()

    def __str__(self):
        return self.name


class Student(models.Model):

    name = models.CharField(
        max_length=100
    )

    courses = models.ManyToManyField(
        Course,
        related_name="students"
    )

    def __str__(self):
        return self.name

Now one Student can have many Courses, and one Course can have many Students.

29. Common ManyToManyField Mistakes

  • Trying to assign a ManyToMany relationship before saving the main object.
  • Forgetting to use add(), set(), or similar relationship methods.
  • Confusing ManyToManyField with ForeignKey.
  • Using the wrong reverse relationship name.
  • Forgetting to run migrations after changing the model.
  • Deleting a Course when only the relationship should be removed.
  • Not using prefetch_related() when loading many related records.
  • Using a normal ManyToManyField when the relationship itself needs extra fields.

30. ManyToManyField Summary

ManyToManyField is used when multiple objects can be connected to multiple objects.

  • It creates a many-to-many relationship.
  • One Student can have many Courses.
  • One Course can have many Students.
  • Django automatically manages an intermediate relationship table.
  • add() adds relationships.
  • remove() removes selected relationships.
  • clear() removes all relationships.
  • set() replaces the current relationships.
  • related_name customizes reverse access.
  • prefetch_related() can optimize many-to-many queries.
  • A custom intermediate model can store extra relationship information.

📌 Key Points

  • ManyToManyField creates a many-to-many relationship.
  • Multiple Students can be connected to multiple Courses.
  • Django manages an intermediate relationship table automatically.
  • Use add() to create relationships.
  • Use remove() to remove selected relationships.
  • Use clear() to remove all relationships.
  • Use set() to replace relationships.
  • related_name provides convenient reverse access.
  • prefetch_related() can improve related-object loading.
  • Use a custom intermediate model when the relationship needs extra fields.

🧠 Quick Quiz

Question: Which Django field is used to create a many-to-many relationship?