I've spent a good amount of time trying to solve a strange problem with Django and I haven't yet found a simple solution to solve it.
The problem isn't occurring in a far fetched edge case situation nor in a complicated setup, which adds up to the frustration. It's a really simple scenario with no complexity involved at all and yet I can't seem to find a way to just make it work, even with the ugliest hacks I can think of.
No rocket science so far, in fact this is pretty much standard stuff.
Soon you think, hey.. wouldn't that be cool if I was sent an email each time an OrderForm is created or modified ?
Nothing could be easier with Django, we just have to hook a post_save signal to the OrderForm model and send an email with mail_send (or django-notification in my case).
If like me you thought it's not a big deal and it can be done easily, you are so wrong !
Before you know it you'll find yourself wondering why the email sent when a new OrderForm is created comes without any OrderFormLines in it and its grand total is zero. Then you'll check in the admin and all the data is there and the grand total is OK.
After some more tests you'll notice that the emails sent for modified OrderForms contains some OrderFormLines and its total is not zero .. however the total is wrong and the OrderFormLines are outdated.
Welcome to hell.
That's when you learn that Django must save the main model (OrderForm) first in order to be able to save the inlines OrderFormLines and that there's no way to know exactly when it gets done.
The logic implied is twofold. First since Django deals with both creates and updates the same way, it must ensure that the main model has been saved in order to proceed to save the related objects, just to be sure the object they're associated with really exist.
The other problem is how signals work, they are blocking. So Imagine an object with many related object, let's say 1000. Your application would hang upon every save if Django had to cycle through the 1000 object to save them one by one before emitting the post_save signal of their parent object.
This leaves me with little to no solutions to my problem. And if you don't believe me let's just see what I've tried so far.
As explained above, signals don't work in this case because they are triggered long before the inlines are saved. But I'll put the code anyway as an example of how simple it should have been.
That's it. I'm out of options and it's really annoying because it's the first time I hit a wall that I can't sidestep or workaround in Django.
The only possible way to get there I can think of is by hooking the signal to the OrderFormLine instead of the actual OrderForm. But this would raise two other issues that are not easy to solve either;
If the OrderForm would contain 20 OrderFormLines the signal would also be triggered 20 times, which means I would need to find a way to isolate the last OrderLine and call the function only on this one
Then I would also need to hook a post_save signal on the OrderForm model anyway in case one of its property get modified and not any OrderFormLine. This means the post_save signal would be called for each OrderFormLine AND for the OrderForm itself. Then I would need to find a way send the notification only once.