🌐
Python Tutorial
pythontutorial.net › home › django tutorial › django many-to-many relationship
Django Many-to-Many Relationships By Practical Examples
January 18, 2023 - To create a many-to-many relationship in Django, you use the ManyToManyField. For example, the following uses the ManyToManyField to create a many-to-many relationship between Employee and Compensation models:
🌐
Sankalpjonna
sankalpjonna.com › learn-django › the-right-way-to-use-a-manytomanyfield-in-django
The right way to use a ManyToManyField in Django
To maintain a many-to-many relationship between two tables in a database, the only way is to have a third table which has references to both of those tables. This table is called a “through” table and each entry in this table will connect the source table (sandwich in this case) and the target table (sauce in this case). ... This is exactly what Django does under the hood when you use a ManyToManyField.
Discussions

The right way to use a ManyToManyField in Django
Where can I read more content like this? Btw very informative content man. Keep posting stuff like this. More on reddit.com
🌐 r/django
22
101
January 31, 2021
Incorporating many-to-many through model across multiple relationships
Hi community!, I have a project that I am trying assign subitems of a model to different instances of another model, yet there are other relations (ForeignKey and another manytomany) in between the outcomes that I am looking. Context: We are building an app that registers different measures ... More on forum.djangoproject.com
🌐 forum.djangoproject.com
6
0
March 22, 2024
python - ManyToMany Relationship between two models in Django - Stack Overflow
The related managers that are added, etc. is all Django logic. Behind the curtains, it will query the table in the middle. You however need to fix the related_name=… parameter [Django-doc]. The related_name specifies the name of the relation in reverse so from Course to Profile in this case. More on stackoverflow.com
🌐 stackoverflow.com
Reading Extra Fields in a ManyToMany ("through") Table
I’m relatively newish to Django, working on a little project to practise what I’m learning. I have a table with a ManyToManyField that specifies a “through table” so that I can add a bit more information to the many-to-many relationship. All works fine and I’ve got some test data, ... More on forum.djangoproject.com
🌐 forum.djangoproject.com
14
0
November 25, 2021
🌐
Django
docs.djangoproject.com › en › 6.0 › topics › db › examples › many_to_many
Many-to-many relationships | Django documentation | Django
What follows are examples of operations that can be performed using the Python API facilities. ... >>> p1 = Publication(title="The Python Journal") >>> p1.save() >>> p2 = Publication(title="Science News") >>> p2.save() >>> p3 = Publication(title="Science Weekly") >>> p3.save() ... >>> a1.publications.add(p1) Traceback (most recent call last): ... ValueError: "<Article: Django lets you build web apps easily>" needs to have a value for field "id" before this many-to-many relationship can be used.
🌐
Agiliq
books.agiliq.com › projects › django-orm-cookbook › en › latest › many_to_many.html
3. How to model many to many relationships? — Django ORM Cookbook 2.0 documentation
Few operations using ManyToManyfield which can be done are: >>> t1 = Tweet(tweet="I am happy today") >>> t1.save() >>> t2 = Tweet(tweet="This is my second Tweet") >>> t2.save() >>> u1 = User(username='johny1', first_name='Johny', last_name='Smith', email='johny@example.com') >>> u1.save() >>> ...
🌐
OpenClassrooms
openclassrooms.com › en › courses › 7107341-intermediate-django › 7265468-create-many-to-many-relationships
Create Many-to-Many Relationships - OpenClassrooms
To create the many-to-many relationship in the view, you first need to define the appropriate form. As the fields are on the User model, you can use a ModelForm . Create a form that allows the user to select other users to follow. # blog/forms.py from django.contrib.auth import get_user_model User = get_user_model() class FollowUsersForm(forms.ModelForm): class Meta: model = User fields = ['follows']
🌐
GeeksforGeeks
geeksforgeeks.org › python › how-to-add-multiple-objects-to-manytomany-relationship-at-once-in-django
How to Add Multiple Objects to ManyToMany Relationship at Once in Django? - GeeksforGeeks
July 23, 2025 - A relationship is said to be many ... of set A. A common real-life example is that an author can write multiple books and at the same time a book can be written by multiple authors....
🌐
REVSYS
revsys.com › home › tidbits › tips for using django's manytomanyfield
Tips for Using Django's ManyToManyField - REVSYS
August 31, 2018 - Jacob Kaplan-Moss also has a great set of examples of using a many-to-many relationship with a custom "through" model. Thank you to Monique Murphy and Jeff Triplett for their assistance. django manytomanyfield through model 2018-08-31T15:37:58.114597-05:00 2018-08-31T15:37:58.114597-05:00 2018-08-31T15:37:58.061032-05:00 2018 django,manytomanyfield,through model
🌐
Django
docs.djangoproject.com › en › 6.0 › topics › db › examples › many_to_one
Many-to-one relationships | Django documentation | Django
🎁 Get PyCharm for 30% off ... To define a many-to-one relationship, use ForeignKey. In this example, a Reporter can be associated with many Article objects, but an Article can only have one Reporter object:
Find elsewhere
🌐
Reddit
reddit.com › r/django › the right way to use a manytomanyfield in django
r/django on Reddit: The right way to use a ManyToManyField in Django
January 31, 2021 -

When you design a database for a large product, it is inevitable to arrive at a point where you have two models that are related to each other in a way that does not get solved using a ForeignKey alone. 

A good example of a many-to-many relationship is the relationship between a sandwich and a sauce. I like a chicken teriyaki sandwich but only if it contains barbeque sauce as well as mayonnaise sauce. So the same sandwich can have multiple sauces. At the same time I want mayonnaise sauce to appear on a turkey sandwich as well, so the same sauce can be used on different kinds of sandwiches.

This is a great place to use the ManyToManyField offered by Django instead of a regular ForeignKey. Unfortunately the way Django deals with this is a bit unintuitive and can be confusing, so I thought it would be best to demonstrate how a many to many relationship works under the hood.

Many-to-many relationship in a database

To maintain a many-to-many relationship between two tables in a database, the only way is to have a third table which has references to both of those tables. This table is called a “through” table and each entry in this table will connect the source table (sandwich in this case) and the target table (sauce in this case).

This is exactly what Django does under the hood when you use a ManyToManyField. It creates a through model which is not visible to the ORM user and whenever one needs to fetch all of the sandwiches that use a particular sauce given only the name of the sauce, the above 3 tables are joined.

Joining 3 tables may not be very efficient, so if you query this information using the sauce ID instead of name, Django internally Joins only 2 tables (sandwiches_sauces and sandwiches). These join operations are invisible to the user but it helps to know what’s going on in the database so that the queries can be made as efficient as possible.

Using the ManyToManyField

Now that we know what happens internally, let’s look at how the ManyToManyField helps abstract out all of this complexity and provides a simple interface to the person writing code.

Let us create a new Django project and an app within it called sandwiches. In models.py, define these two models.

from django.db import models

class Sauce(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Sandwich(models.Model):
    name = models.CharField(max_length=100)
    sauces = models.ManyToManyField(Sauce)

    def __str__(self):
        return self.name

And that’s it. Running a database migration on these models will create a Sandwich table, a Sauce table and a through table connecting the two. Let us now look at how we can access this information using the Django ORM.

Fetching all sandwiches and sauces using each other

Let us create some data in the Sandwich and Sauce models and see how we can retrieve them.

>>> chicken_teriyaki_sandwich = Sandwich.objects.create(name="Chicken Teriyaki Sandwich")
>>> bbq_sauce = Sauce.objects.create(name="Barbeque")
>>> mayo_sauce = Sauce.objects.create(name="Mayonnaise")
>>> 
>>> chicken_teriyaki_sandwich.sauces.add(bbq_sauce)
>>> chicken_teriyaki_sandwich.sauces.add(mayo_sauce)
>>> 
>>> chicken_teriyaki_sandwich.sauces.all()
<QuerySet [<Sauce: Barbeque>, <Sauce: Mayonnaise>]>
>>> 

Running sandwich.sauces.all() gives us all the sauces applied on that Sandwich but if we want to perform a reverse action, i.e get all the sandwiches that use a particular sauce, this can be done by performing the same operation on the target object by using a _set.

>>> bbq_sauce = Sauce.objects.get(name="Barbeque sauce")
>>> 
>>> bbq_sauce.sandwich.all()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'Sauce' object has no attribute 'sandwich'
>>> 
>>> 
>>> bbq_sauce.sandwich_set.all()
<QuerySet [<Sandwich: Chicken Teriyaki>]>
>>> 

As  you can see, trying to perform a bbq_sauce.sandwich.all() threw a AttributeError but bbq_sauce.sandwich_set.all() worked. This is because Django internally references a target ManyToManyField as a set. This behaviour can be overridden by providing a related_name option to the target field.

class Sandwich(models.Model):
    name = models.CharField(max_length=100)
    sauces = models.ManyToManyField(Sauce, related_name="sandwiches")

    def __str__(self):
        return self.name

Now we can perform the previous query using sandwiches instead of sandwiches_set.

>>> 
>>> 
>>> bbq_sauce = Sauce.objects.get(name="Barbeque sauce")
>>> bbq_sauce.sandwiches.all()
<QuerySet [<Sandwich: Chicken Teriyaki>]>
>>> 
>>> 

In simpler words, a related name is the phrase that you would like to use instead of a *_set.

The recommended way to choose a related name is to use the plural form of your model name in lowercase.

Fetching specific sandwiches and sauces using each other

In the above examples, we were fetching all entries in the table using a .all() function, but in most practical cases, we would want to query a subset of the data. For instance we might want to query all the sandwiches that use barbeque sauce. This can be done with a query like this:

>>> 
>>> Sandwich.objects.filter(sauces__name="Barbeque sauce")
<QuerySet [<Sandwich: Chicken Teriyaki>]>
>>> 
>>> 

But like I mentioned before, to perform this query Django internally has to join all the 3 tables. We can make this more efficient by querying using the sauce ID instead of name. This will enable Django to join only the Sandwich table and the through table.

>>> 
>>> Sandwich.objects.filter(sauces__id=1)
<QuerySet [<Sandwich: Chicken Teriyaki>]>
>>> 
>>> 
>>> 

You can also query this information in reverse, i.e fetch all sauces that are put on a particular sandwich.

>>> 
>>> Sauce.objects.filter(sandwich__name="Chicken Teriyaki")
<QuerySet [<Sauce: Barbeque sauce>, <Sauce: Mayonnaise sauce>]>
>>> 
>>> 
>>> 

Even in this case I would recommend querying using the sandwich ID to make this query more efficient.

Adding Items from either side of the relationship

So far we have been adding sauces to the sandwich model but we can also go the other way round pretty easily. Django internally takes care of whatever database table entries need to be created to make this happen.

The only gotcha is that if you don’t plan to use a related_name, you would have to add the item to a *_set attribute.

>>> 
>>> 
>>> sandwich = Sandwich.objects.get(name="Turkey")
>>> 
>>> mayo_sauce = Sauce.objects.get(name="Mayonnaise sauce")
>>> 
>>> mayo_sauce.sandwich_set.add(sandwich)
>>> 
>>> 

Using a custom “through” model

Even though Django takes care of creating the through model on its own and keeps this invisible to a user, sometimes it becomes necessary to use a custom through model in order to add some additional fields to that model.

For instance consider the relationship between a student and a teacher. A teacher can teach multiple students and a student can be taught by multiple teachers thereby qualifying this for a many to many relationship. 

However in this case just having a table that connects these two entities won’t suffice because we would require extra information such as:

  • The date on which a teacher started teaching a student.

  • The subject that is taught by a teacher to a student.

  • Duration of the course.

To sum this up, we require a “course” table that not only connects a student and a teacher but also holds this extra information.

To make this happen, one must override the default though table that Django creates and use a custom through table instead.

Extra sauce please!

Ok enough talk about students and teachers, let’s get back into the topic that probably interested you in this blog post in the first place - food!

In all of the above examples of Sandwiches and sauces, the only information we have is what sauces go on what sandwiches but what if someone wants to put extra sauce of the same kind on a sandwich? 

You could try adding the same sauce model to a sandwich model multiple times but Django would simply ignore it as the add function is idempotent. You can add a particular sauce to a Sandwich only once. To solve this problem we can use a custom through model.

Note: Do keep in mind that if you want to go down this road you must do this from the start or be okay with dropping your database and starting from scratch because Django does not allow you to create a custom through model after previously using a default through model. If you try this you may see weird errors like this one:

raise ValueError(
ValueError: Cannot alter field sandwiches.Sandwich.sauces into sandwiches.Sandwich.sauces - they are not compatible types (you cannot alter to or from M2M fields, or add or remove through= on M2M fields)

Creating a custom through model:

from django.db import models

class Sauce(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Sandwich(models.Model):
    name = models.CharField(max_length=100)
    sauces = models.ManyToManyField(Sauce, through='SauceQuantity')

    def __str__(self):
        return self.name

class SauceQuantity(models.Model):
    sauce = models.ForeignKey(Sauce, on_delete=models.CASCADE)
    sandwich = models.ForeignKey(Sandwich, on_delete=models.CASCADE)
    extra_sauce = models.BooleanField(default=False)

    def __str__(self):
        return "{}_{}".format(self.sandwich.__str__(), self.sauce.__str__())

With a custom through model you will not be able to add sauces to a Sandwich like you did before. Instead you would have to create entries of the SauceQuantity model explicitly as shown below.

>>> from sandwiches.models import *
>>> 
>>> 
>>> chicken_teriyaki_sandwich = Sandwich.objects.create(name="Chicken Teriyaki with mayo and extra bbq sauce")
>>> 
>>> 
>>> bbq_sauce = Sauce.objects.create(name="Barbeque")
>>> 
>>> SauceQuantity.objects.create(sandwich=chicken_teriyaki_sandwich, sauce=bbq_sauce, extra_sauce=True)
<SauceQuantity: Chicken Teriyaki with mayo and extra bbq sauce_Barbeque>
>>> 
>>> SauceQuantity.objects.create(sandwich=chicken_teriyaki_sandwich, sauce=mayo_sauce, extra_sauce=False)
<SauceQuantity: Chicken Teriyaki with mayo and extra bbq sauce_Mayonaisse>
>>>

You can still access a sauce from a sandwich and a sandwich from a sauce just like you previously did.

>>> 
>>> chicken_teriyaki_sandwich.sauces.all()
<QuerySet [<Sauce: Barbeque>, <Sauce: Mayonnaise>]>
>>> 
>>> bbq_sauce.sandwich_set.all()
<QuerySet [<Sandwich: Chicken Teriyaki with mayo and extra bbq sauce>]>
>>> 
>>> 

In order to know what all sauces are being used on a sandwich and in what quantities, we can iterate through the sauces of a Sandwich and retrieve information from the SauceQuantity model for each of the sauces as shown below.

>>> 
>>> 
>>> for sauce in chicken_teriyaki_sandwich.sauces.all():
...  saucequantity = SauceQuantity.objects.get(sauce=sauce, sandwich=chicken_teriyaki_sandwich)
...  print("{}{}".format("Extra " if saucequantity.extra_sauce else "", sauce))
... 
Extra Barbeque
Mayonnaise
>>> 

The SauceQuantity model can also be extended further to include stuff like whether or not the sandwich is cut in half, type of bread used, etc. 

Closing notes

The ManyToManyField may be confusing but it is very handy. Any type of confusion you may have can be resolved with the right documentation. Here are a few that really helped me.

  • The official Django documentation that covers many-to-many relationships which you can find here.

  • A great example on when to use a custom through model found here.

Originally posted on my blog

🌐
Django Forum
forum.djangoproject.com › using django › using the orm
Incorporating many-to-many through model across multiple relationships - Using the ORM - Django Forum
March 22, 2024 - Hi community!, I have a project that I am trying assign subitems of a model to different instances of another model, yet there are other relations (ForeignKey and another manytomany) in between the outcomes that I am looking. Context: We are building an app that registers different measures ...
🌐
Medium
medium.com › django-rest › many-to-many-relationship-manytomanyfield-9b8201d879ab
Many-To-Many Relationship (ManyToManyField) | by Emre Cevik | Python | Django & Rest | Medium
April 4, 2022 - You can access the “CarModel” instances that are related to your “FuelType“ instance by going fueltype_instance.models.all(). You can no longer use carmodel_set. $ gas.models.all()<QuerySet [ <CarModel: C180>, <CarModel: C200> ]> Many-to-many relationships can be queried using lookups across relationships:
🌐
Medium
medium.com › swlh › django-forms-for-many-to-many-fields-d977dec4b024
Django Forms for Many-to-Many Fields | by Alice Ridgway | The Startup | Medium
June 26, 2022 - Use cases include: A user needs to assign multiple categories to a blog post · A user wants to add multiple blog posts to a publication · In this case, the user needs to be able to add multiple members to a meal.
Top answer
1 of 2
16

For a relational databases, the model where you define the ManyToManyField does not matter. Django will create an extra table with two ForeignKeys to the two models that are linked by the ManyToManyField.

The related managers that are added, etc. is all Django logic. Behind the curtains, it will query the table in the middle.

You however need to fix the related_name=… parameter [Django-doc]. The related_name specifies the name of the relation in reverse so from Course to Profile in this case. It thus should be something like 'profiles':

class Profile(AbstractUser):
    bio = models.TextField()
    image = models.ImageField(default='defaults/user/default_u_i.png', 
    courses = models.ManyToManyField('home.Course', related_name='profiles')

    def __str__(self):
        return self.username

You thus can obtain the people that particiate in a Course object with:

mycourse.profiles.all()

and you can access the courses in which a Profile is enrolled with:

myprofile.courses.all()

For more information, see the Many-to-many relationships section of the documentation.

You can add a course to the courses of a user with:

@login_required
def course_add(request):
    if request.method == 'POST':
        form = CourseForm(request.POST)
        if form.is_valid():
            course = form.save()
            request.user.courses.add(course)
    else:
        form = CourseForm()
    context = {
        'form': form
    }
    return render(request,'home/courses/course_add.html', context)
2 of 2
0

You don't need to add the related name. Default is "courses_set" in your case. Here is excerpt from: https://docs.djangoproject.com/en/dev/topics/db/queries/#backwards-related-objects

Following relationships “backward” If a model has a ForeignKey, instances of the foreign-key model will have access to a Manager that returns all instances of the first model. By default, this Manager is named FOO_set, where FOO is the source model name, lowercased. This Manager returns QuerySets, which can be filtered and manipulated as described in the “Retrieving objects” section above.

🌐
Python Tutorial
pythontutorial.net › home › django tutorial › django manytomanyfield through
Django ManyToManyField Through - Python Tutorial
January 19, 2023 - First, define the Job model, add the employees attribute that uses the ManyToManyField, and pass Assignment as the through argument. Second, define the Assignment class that has two foreign keys, one links to the Employee model, and the other ...
🌐
CodeSignal
codesignal.com › learn › courses › advanced-database-schema-design-in-django › lessons › many-to-many-relationship-basics
Many-to-many Relationship: Basics
You can add multiple tags to each todo item, and each tag can be added to multiple todo items. This is called a many-to-many relationship. We'll use two models: Tag and Todo. Each Todo task can have multiple Tags, and each Tag can be associated with multiple Todo tasks. We achieve this in Django using the ManyToManyField.
🌐
Readthedocs
djangodocs.readthedocs.io › en › latest › topics › db › examples › many_to_many.html
Many-to-many relationships — Django 1.5 documentation
In this example, an Article can be published in multiple Publication objects, and a Publication has multiple Article objects: from django.db import models class Publication(models.Model): title = models.CharField(max_length=30) def __unicode__(self): return self.title class Meta: ordering = ...
🌐
Medium
medium.com › django-unleashed › mastering-manytomanyfield-in-django-a-comprehensive-guide-to-effective-relationship-management-988156073f5d
Mastering ManyToManyField in Django: A Comprehensive Guide to Effective Relationship Management | by Mehedi Khan | Django Unleashed | Medium
February 15, 2025 - This example demonstrates how to fetch related records efficiently. Mastering Containerization: Writing Dockerfile and Docker-Compose for PostgreSQL Bliss! 🐳✨ · When working with forms involving many-to-many relationships, consider using the ModelMultipleChoiceField. This field simplifies the process of handling multiple choices in a form: # forms.py from django import forms from .models import Student class StudentForm(forms.ModelForm): class Meta: model = Student fields = ['name', 'courses'] widgets = { 'courses': forms.CheckboxSelectMultiple, }
🌐
DEV Community
dev.to › guzmanojero › whats-the-use-of-intermediate-models-in-django-many-to-many-relationship-40li
What's the use of Intermediate models in Django (Many to Many Relationship) - DEV Community
November 16, 2025 - The Students and Courses example is a classic demonstration of a many-to-many relationship, as a student can enroll in multiple courses, and a course can have multiple students. You'll define the relationship by placing the ManyToManyField on ...
🌐
Django Forum
forum.djangoproject.com › using django › using the orm
Reading Extra Fields in a ManyToMany ("through") Table - Using the ORM - Django Forum
November 25, 2021 - I’m relatively newish to Django, working on a little project to practise what I’m learning. I have a table with a ManyToManyField that specifies a “through table” so that I can add a bit more information to the many-to-many relationship. All works fine and I’ve got some test data, ...
🌐
GitHub
gist.github.com › jacobian › 827937
An example of using many-to-many "through" to augment m2m relationships. See http://www.quora.com/How-do-you-query-with-a-condition-on-a-ManyToMany-model-in-Django for context. · GitHub
September 14, 2020 - An example of using many-to-many "through" to augment m2m relationships. See http://www.quora.com/How-do-you-query-with-a-condition-on-a-ManyToMany-model-in-Django for context. - models.py