~2 min read • Updated Mar 10, 2026
1. Defining a Many‑to‑Many Relationship
To define a many‑to‑many relationship, Django provides ManyToManyField.
In the example below, an Article can appear in multiple Publication objects, and each Publication can contain multiple Articles.
class Publication(models.Model):
title = models.CharField(max_length=30)
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
2. Creating Data
Creating Publication instances:
p1 = Publication(title="The Python Journal"); p1.save()
p2 = Publication(title="Science News"); p2.save()
p3 = Publication(title="Science Weekly"); p3.save()
Creating an Article:
a1 = Article(headline="Django lets you build web apps easily")
You cannot add M2M relations before saving:
a1.publications.add(p1) # Error
Save first:
a1.save()
a1.publications.add(p1)
3. Adding Multiple Relations
a2 = Article(headline="NASA uses Python"); a2.save()
a2.publications.add(p1, p2)
a2.publications.add(p3)
Adding duplicates is safe:
a2.publications.add(p3)
Adding the wrong type raises an error:
a2.publications.add(a1) # TypeError
4. Creating and Adding in One Step
new_pub = a2.publications.create(title="Highlights for Children")
5. Accessing Related Objects
From Article → Publication:
a1.publications.all()
a2.publications.all()
From Publication → Article (reverse relation):
p1.article_set.all()
p2.article_set.all()
6. Querying Many‑to‑Many Relationships
Filtering by ID or object:
Article.objects.filter(publications__id=1)
Article.objects.filter(publications=p1)
Filtering by fields on the related model:
Article.objects.filter(publications__title__startswith="Science")
Use distinct() to avoid duplicates:
Article.objects.filter(publications__title__startswith="Science").distinct()
Filtering with lists:
Article.objects.filter(publications__in=[p1, p2]).distinct()
7. Reverse M2M Queries
Publication.objects.filter(article__headline__startswith="NASA")
Publication.objects.filter(article__in=[a1, a2]).distinct()
8. Removing Relations
From the Article side:
a4.publications.remove(p2)
From the Publication side:
p2.article_set.remove(a5)
9. Using set() and clear()
Setting the entire relation:
a4.publications.set([p3])
Clearing all relations:
a4.publications.clear()
p2.article_set.clear()
10. Behavior When Deleting Objects
Deleting a Publication:
p1.delete()
a1.publications.all() # Empty
Deleting an Article:
a2.delete()
p2.article_set.all() # Empty
11. Bulk Deletes and M2M Cleanup
Bulk delete Publications:
Publication.objects.filter(title__startswith="Science").delete()
a2.publications.all() # Only remaining items
Bulk delete Articles:
q = Article.objects.filter(headline__startswith="Django")
q.delete()
q.all() # Empty
Conclusion
Django’s ManyToManyField provides a powerful and flexible way to model complex relationships.
With methods like add(), remove(), set(), clear(), and create(), you can fully manage M2M relations.
Django also supports rich querying from both sides of the relationship and handles cleanup automatically when objects are deleted.
Written & researched by Dr. Shahin Siami