Search code examples
djangodjango-modelsdjango-querysetdjango-ormdjango-related-manager

Django: How to efficiently add objects to ManyToManyFields of multiple objects?


We have a student and class many to many relation, where a student can take multiple classes, and a class can be taken by multiple students.

class Class(models.Model):
    name = models.CharField(null=False, max_length=128)

class Student(models.Model):
    first_name = models.CharField(null=False, max_length=64)
    classes = ManyToManyField(Class)

What is the fastest way to add some object or a whole QueryList (in our case: all classes with Biology in their name), to the ManyToManyField of each object in another QueryList (in our case: all students whose first name is Linus)?

The current way I am doing it is:

biology_classes = Class.objects.filter(name__contains='Biology')
linuses = Student.object.filter(first_name='Linus')
for linus in linuses:
    linus.classes.add(*biology_classes)

Which I guess hits the db for each student. I wonder if there is maybe some way to do it all "at once". Maybe something that looks something like this:

linuses.classes.add(*biology_classes) # (this does not work)

Solution

  • You can bulk create a record for each combination with a single query:

    biology_classes = Class.objects.filter(name__contains='Biology')
    linuses = Student.object.filter(first_name='Linus')
    
    StudentClass = Student.classes.through
    items = [
        StudentClass(student=student, class=class)
        for student in linuses
        for class in biologoy_classes
    ]
    
    StudentClass.objects.bulk_create(items)

    This thus will make a total of three queries:

    1. one query to fetch the relevant Classes;
    2. one query to fetch the relevant Students; and
    3. one query to create all connections between the Classes and Students.