Eduard Luca
Eduard Luca

Reputation: 6611

Add Many-To-Many objects to model inside save() method in Django

I have overridden my save() method on a model, in order to add some ManyToMany objects to it. If I call the super().save() method after I add the objects, I get the classic error that a model needs a PK before adding ManyToMany objects, which is normal. However If I call it both before and after, the objects simply don't get added.

My code looks like this:

def save(self, force_insert=False, force_update=False):
        super(Teacher, self).save(force_insert, force_update)

        from school.models import Course

        disciplinary = Course.objects.filter(type=Course.TYPE_DISCIPLINARY)

        for disc in disciplinary:
            print disc  # this gets called
            self.subjects.add(disc)

        super(Teacher, self).save(force_insert, force_update)

This produces no errors, but doesn't add the appropriate Courses.

Upvotes: 0

Views: 772

Answers (3)

Anentropic
Anentropic

Reputation: 33853

If you are using the Django admin there is a gotcha... when saving your parent object the admin will first call save() on your model instance, then it will add the m2m objects that were submitted in the admin form... whatever was selected in the admin form will then replace the objects you add in your overridden save method.

Upvotes: 2

Eduard Luca
Eduard Luca

Reputation: 6611

What I ended up doing was to delay adding of the courses, by using Celery (which I was using anyway on this project), by 5 seconds, at which point DB should be consistent and everything should be available for me to use.

The more reliable solution was to only delay the Celery task by a small amount (<1 second) and re-schedule it if the entry doesn't exist in the DB yet. (It seems that Django doesn't persist the models in the DB right away, but caches them, so that you can get() them in certain places)

Upvotes: 0

Adam Barabasz
Adam Barabasz

Reputation: 21

Seeing that you add just a static course set, you could use post_save signals Django signals post save signal

If it's not a problem just add a new function and call it after save

Teacher.save()
Teacher.save_courses()

I personally don't know a way to make it in the save function, but i can be wrong.

Upvotes: 0

Related Questions