OBu OBu - 6 months ago 42
Python Question

Django ManyToMany access in save() function

I want to create additional objects based on user input during the .save() method of my model. the info is stored in a ManyToMany-relation

.available_specs
.

My code works, if one presses save twice, but not at the first time. The problem is described in the comments here Django foreign key access in save() function, too.

Here is what I do:

def save(self, *args, **kwargs):

my_save_result = super().save(*args, **kwargs) #save first to create an id
self.refresh_from_db() #just as a test, did not help at all

#the following line is the problem:
# in the first save, available_specs.all() returns []
# when I re-open the model and save again, I get the correct list
for spec in self.available_specs.all():
VehicleSpec.objects.get_or_create(vehicle=self, spec=spec)

return my_save_result


I'm using Python 3.5 and Django 1.9

Edit:
I tried to use the
post_save()
signal using the following code (and removed the overridden save()-method):

@receiver(post_save, sender=VehicleModel)
def create_dependent_vehicle_specs(sender, **kwargs):
vehicle = kwargs['instance']

#in the first save-process I get an empty list here,
#after I hit save again, the code works.
print(vehicle, vehicle.available_specs.all())
for spec in vehicle.available_specs.all():
VehicleSpec.objects.get_or_create(vehicle=vehicle, spec=spec)


Edit2: m2m_changed did the trick:

@receiver(m2m_changed, sender=VehicleModel)
def create_dependent_vehicle_specs(sender, **kwargs):
vehicle = kwargs['instance']
for spec in vehicle.available_specs.all():
VehicleSpec.objects.get_or_create(vehicle=vehicle, spec=spec)

m2m_changed.connect(create_dependent_vehicle_specs, sender=VehicleModel.available_specs.through) # @UndefinedVariable


BTW: A related question is here: Django accessing ManyToMany fields from post_save signal

Answer

You need to use a m2m_changed signal. You should not be calling another models' get_or_create in another models' save method