1

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)
talz
  • 1,004
  • 9
  • 22

1 Answers1

2

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.
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555