Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django post_save signal sends outdated inline formsets

Consider the following:

class OrderForm(models.Model):
    title = models.CharField(max_length=100)
    desc  = models.TextField()


class OrderFormLine(models.Model):
    order = models.ForeignKey(OrderForm)
    lagel = models.CharField(max_length=100)
    qty   = models.IntegerField(...)
    price = models.FloatField(...)

Now I want to send an email with the orderform details whenever someone creates one or modify one.

No rocket science so far .. let's just use a post_save signal;

post_save.connect(email_notify, sender=OrderForm)

But there's one tiny problem, the OrderForm object passed to email_notify is updated with the new data as expected, but not the related OrderFormLine items.

I've tried to override the save methods in the admin AND in the model, I've tried to save the object, the form and its relation before passing it to my notification handler, nothing works.

I'm aware that I could attach the post_save signal to the OrderItem model, but then the email would be sent for each items.

Help I'm on the brink of madness.

UPDATE:

Found a simple and reliable solution

Short story:

def email_notify_orderform(sender, **kwargs):
    instance = kwargs['instance']
    ct = ContentType.objects.get_for_model(OrderForm)
    if ct.id == instance.content_type.id:
        print instance.is_addition()
        print instance.is_change()
        print instance.is_deletion()
        print instance.change_message
        print instance.action_time
        print instance.get_edited_object().total() # BINGO !
post_save.connect(email_notify_orderform, sender=LogEntry)
like image 707
h3. Avatar asked Nov 06 '10 03:11

h3.


1 Answers

The basic problem is that when the main objects post_save signal is sent, the inlines have not been saved yet: the parent model always gets saved first. So, it's not that it's sending old data; in fact it's the current state of the data.

The simplest solution is to create a custom signal and have that signal sent at a place where the inlines have been saved. The save_formset method on ModelAdmin is your hook.

like image 138
Chris Pratt Avatar answered Oct 04 '22 02:10

Chris Pratt