Milano
Milano

Reputation: 18705

Django post_save signal acts like pre_save

I'm trying to create a simple signal which creates an identifier for the model.

class Scheduler(models.Model):
    weekhours = models.ManyToManyField('WeekHour', related_name='schedulers')
    identificator = models.TextField(null=True,blank=True)

class WeekHour(models.Model):
    hour = models.PositiveSmallIntegerField(verbose_name='Hour in week (0 - 7*24')

Everytime when Scheduler object is saved, I want to create or update the identificator joining a list of [weekhour_obj.hour for weekhour_obj in scheduler.weekhours.all()]

So I created a post_save signal. The problem is that when I save Scheduler, the signal acts like it was pre_save. The workhours set for the scheduler is the old one, not updated. When I save it second time it works.

@receiver(post_save,sender=models.Scheduler)
def set_identificator(sender,created,instance,**kwargs):
    identificator = ','.join([str(x.hour) for x in instance.weekhours.all().order_by('hour')])
    models.Scheduler.objects.filter(pk=instance.pk).update(identificator = identificator)

Do you know where is the problem?

EDIT - Example:

When I put print instance.weekhours.all() to the first line in the signal method it acts this way:

  1. Created a scheduler object in Django admin with weekhours with hour 2 and hour 4. It printed nothing.
  2. Opened scheduler in admin and changed WeekHours from 2 and 4 to 5. It printed <QuerySet [<WeekHour: 2>,<WeekHour: 4>]>
  3. Opened scheduler again and changed weekhours to 6 and 7. It printed <QuerySet [<WeekHour: 5>]>

But it is a post_save signal so why it acts like it was pre_save?

Upvotes: 1

Views: 587

Answers (1)

Messaoud Zahi
Messaoud Zahi

Reputation: 1232

Many-to-many relationships require the parent object to be saved first , You can’t associate items with a Scheduler instance until it’s been saved.

In your example you are trying to get instance.weekhours.all() in post_save but it will return always None in the first save. for that you need to do another save to get values.

You can use m2m_changed instead of post_save to create the identificator

Upvotes: 3

Related Questions