Use: object.m2mfield.add(*items) as described in the documentation:

add() accepts an arbitrary number of arguments, not a list of them.

add(obj1, obj2, obj3, ...)

To expand that list into arguments, use *

add(*[obj1, obj2, obj3])

Addendum:

Django does not call obj.save() for each item but uses bulk_create(), instead.

Answer from Yuji 'Tomita' Tomita on Stack Overflow
🌐
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

Discussions

Save many-to-many relationship after use the add() method on the field to add a record
I have models Book and I want to save new record this book after every update information about this book (duplicate information). Wherein, I want that main book don’t save in database, only duplicate information in database. All fields are stored normally except “many-to-many” I have ... More on forum.djangoproject.com
🌐 forum.djangoproject.com
11
0
May 19, 2022
django 1.4 Many-to-Many bulk add - Stack Overflow
I was wondering if there is the equivalent of a "add all" or "bulk create" for many to many relationships which reduce the number of queries (I will be doing this for a long list)? The docs on this More on stackoverflow.com
🌐 stackoverflow.com
How do I set the value of a Many to Many field programmatically?
I am trying to set the value of a tag to “Bought” but I just can’t figure it out. background : I have created a form to buy stock and when a person buys stock I want the value of that trade to be set to “bought”, but I just can’t figure it out. I am putting some code below (not ... More on forum.djangoproject.com
🌐 forum.djangoproject.com
0
1
January 2, 2021
python - How to use add(), set() and clear() methods of ManyRelatedManager in Django ManyToManyField with a through class? - Stack Overflow
I can't find the django doc for it. however looking at the Django3.1's source code of ManyRelatedManager__add, it accepts through_defaults parameter More on stackoverflow.com
🌐 stackoverflow.com
🌐
Sankalpjonna
sankalpjonna.com › learn-django › the-right-way-to-use-a-manytomanyfield-in-django
The right way to use a ManyToManyField in Django
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.
🌐
Django
django.readthedocs.io › en › stable › ref › models › relations.html
Related objects reference — Django 5.2.9 documentation
For many-to-many relationships add() accepts either model instances or field values, normally primary keys, as the *objs argument. Use the through_defaults argument to specify values for the new intermediate model instance(s), if needed. You can use callables as values in the through_defaults ...
🌐
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 - In this article, we will walk through adding multiple objects to a Many-to-Many relationship at once in Django, covering both methods to achieve this efficiently. A relationship is said to be many to many if an element of set A can be associated with multiple elements of set B and a single ...
🌐
REVSYS
revsys.com › home › tidbits › tips for using django's manytomanyfield
Tips for Using Django's ManyToManyField - REVSYS
August 31, 2018 - This is because a ManyToManyField creates an invisible "through" model that relates the source model (in this case Pizza, which contains the ManyToManyField) to the target model (Topping). In order to create the connection between a pizza and a topping, they both have to be added to this invisible "through" table. From the Django docs:
Find elsewhere
🌐
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 - Create and add a FuelType to a CarModel in one step using create(): $ c200.fueltype.create(name="Bio Diesel")<FuelType: Bio Diesel>$ c200.fueltype.all()<QuerySet [ <FuelType: Gas>, <FuelType: Diesel>, <FuelType: Hybrid>, <FuelType: Bio Diesel> ]>$ FuelType.objects.all()<QuerySet [ <FuelType: Gas>, <FuelType: Diesel>, <FuelType: Hybrid>, <FuelType: Bio Diesel> ]> $ gas.carmodel_set.all()<QuerySet [ <CarModel: C180>, <CarModel: C200> ]>$ FuelType.objects.get(name="Gas").carmodel_set.all()<QuerySet [ <CarModel: C180>, <CarModel: C200> ]>
🌐
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
>>> u2.tweet.add(t1) >>> u2.save() >>> u2.tweet.add(t2) >>> u2.save() // User can follow other users. >>> u2.follow.add(u1) >>> u2.save() // Tweets are linked to the users. Users have folloewd each other. Now we can make users do favourite/unfavourite of the tweets.
🌐
Django
docs.djangoproject.com › en › 3.2 › topics › db › examples › many_to_many
Many-to-many relationships | Django documentation | Django
May 10, 2021 - If we delete an Article, its Publications won’t be able to access it: >>> a2.delete() >>> Article.objects.all() <QuerySet [<Article: Django lets you build Web apps easily>]> >>> p2.article_set.all() <QuerySet []> ... >>> a4 = Article(headline='NASA finds intelligent life on Earth') >>> a4.save() >>> p2.article_set.add(a4) >>> p2.article_set.all() <QuerySet [<Article: NASA finds intelligent life on Earth>]> >>> a4.publications.all() <QuerySet [<Publication: Science News>]>
🌐
Learning About Electronics
learningaboutelectronics.com › Articles › How-to-add-or-remove-an-object-ManyToManyField-in-Django.php
How to Add or Remove an Object From a ManyToManyField in Django
We then add to the ShoppingCart model through the statement, shoppingcart.products.add(productobj) We add to the products row of the ShoppingCart model. Therefore, we have, shoppingcart.products · The add() function allows us to add an object to this ManyToManyField. And this is how to add ...
🌐
Django
docs.djangoproject.com › en › 3.2 › ref › models › relations
Related objects reference | Django documentation | Django
May 10, 2021 - For many-to-many relationships add() accepts either model instances or field values, normally primary keys, as the *objs argument. Use the through_defaults argument to specify values for the new intermediate model instance(s), if needed.
🌐
DEV Community
dev.to › danielcoker › updating-a-many-to-many-relationship-5h2j
Updating A Many-To-Many Relationship In Django - DEV Community
February 25, 2022 - One approach is to delete all of the tags associated with the post and then re-add them. However, in this article, we'll use the set method to update their relationship. To follow this article, I'm assuming you have a Django project with a Django Rest Framework installed.
🌐
OpenClassrooms
openclassrooms.com › en › courses › 7107341-intermediate-django › 7265468-create-many-to-many-relationships
Create Many-to-Many Relationships - OpenClassrooms
We set the unique_together attribute in the Meta class to ensure that there is only one instance of BlogContributor for each contributor - blog pairing. Now add a ManyToManyField to Blog and tell it to use our intermediary table.
🌐
Django Forum
forum.djangoproject.com › using django
How do I set the value of a Many to Many field programmatically? - Using Django - Django Forum
January 2, 2021 - I am trying to set the value of a tag to “Bought” but I just can’t figure it out. background : I have created a form to buy stock and when a person buys stock I want the value of that trade to be set to “bought”, but I just can’t figure it out. I am putting some code below (not al of it, just the part you might need) The Bold part is where I have a problem. the model : class Trade(models.Model): trader = models.ForeignKey(User_Info, null=True, on_delete = models.SET_NULL ) ticker...
Top answer
1 of 2
3

I would make this changes to the models to start.

  • Be carefull with the reserved word class, it must be all lowercase.

  • When you define the classes, the order is important. The classes that inherit or are backward-related must be defined last. (eg: Bank must be defined after Customer, if not you'll have an error like "Customer is not defined" or something like that).

  • I think that you may need a name attribute/field in the Bank model. I mean, banks have a name.

  • In the Bank class I think it's better to explicitly use the related name keyword: related_name='banks'. It makes readability better.

  • It's more Pythonic to name classes using the CapWords convention (PEP 8). Use BankCustomer instead of Bank_customer model.


About your specific question.

I did this:

c1 = Customer(name="Guido van Rossum")
c1.save()
b1 = Bank(name="Bank of America")
b1.save()

Then I did b1.customers.add(c1) and this error was raised: IntegrityError: NOT NULL constraint failed: app2_bankcustomer.city_id. It seems that it was expecting city_id to have null=True in the BankCustomer.

I continued with:

ct1 = City('New York')
ct1.save()
bc1 = BankCustomer(customer=c1, bank=b1, city=ct1)
bc1.save()

And then when I did b1.customers.add(c1) no errors were raised.

The problem is the IntegrityError error, apparently:

django.db.utils.IntegrityError: NOT NULL --> this is a very common error for beginners. It means that you have a field that is null=False (aka the default) and you're trying to create that model WITHOUT that field having any data. (source)

So you can make a little change to the BankCustomer. You add null=True in the city field.

class BankCustomer(models.Model):
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
    bank = models.ForeignKey(Bank, on_delete=models.CASCADE)
    city = models.ForeignKey(City, null=True, on_delete=models.CASCADE)

    def __str__(self):
        return f'{self.customer} - {self.bank} - {self.city}'

(Don't forget to run makemigrations and migrate)

After this, no errors are raised.

Some other sources that discuss the issue:

django.db.utils.IntegrityError: NOT NULL constraint failed: app.area_id

django.db.utils.IntegrityError: NOT NULL constraint failed: products_product.image ERROR WITH IMAGE FIELD

https://code.djangoproject.com/ticket/21783

https://forum.djangoproject.com/t/polls-not-null-constraint-failed/4396/2

https://github.com/sibtc/django-beginners-guide/issues/20


If you check the admin you'll see that the Bank model only accepts name and no customers.

Which I think is logical because you want to use the BankCustomer (in your code: Bank_customer).

I hope this helps.

2 of 2
2

I can't find the django doc for it. however looking at the Django3.1's source code of ManyRelatedManager__add, it accepts through_defaults parameter

def add(self, *objs, through_defaults=None):
...
                self._add_items(
                    self.source_field_name, self.target_field_name, *objs,
                    through_defaults=through_defaults,
                )
...

so, instead of

bank.customers.add(customer)

try

bank.customers.add(customer, through_defaults={'city_id':SOME_CITY_OBJ_ID_YOU_WANT})

this works on .set() function as well

🌐
Adrienne Domingus
adriennedomingus.com › tech › django-adding-an-intermediate-model-to-a-manytomany-field-without-one
Django Adding an Intermediate Model to a Manytomany Field Without One - Adrienne Domingus
At this point, you’re finished with the transition, and you can add fields to your intermediate model the way you would usually add new fields — I ran another migration that added the new fields with null=True, pushed the code to make sure all fields were being populated, and then had a final clean-up migration to remove null=True from the fields that didn’t need it. All the rows in your original database table will automatically be available in the new CourseTag model, since they use the same database table. Keep in mind that there are some differences to the Django API depending on what type of many to many field you’re using, so you may need to update some of your database queries for related objects using the through table correctly — namely that you can no longer run a query on the Tag table directly referencing courses.
🌐
GeeksforGeeks
geeksforgeeks.org › how-to-make-many-to-many-field-optional-in-django
How to Make Many-to-Many Field Optional in Django - GeeksforGeeks
September 24, 2024 - In conclusion, the ManyToMany field in Django is by default optional field and no need extra configuration to make optional. However, we have null=True and blank=True to set a Django Model field optional at the database level and at the form level.