Update the parent model when a related (inline) model changed?

324 views
Skip to first unread message

Carsten Fuchs

unread,
Aug 25, 2011, 10:19:30 AM8/25/11
to django...@googlegroups.com
Dear Django list,

what is the best way to automatically update a parent model when one of
it's related models (i.e. the "inline" models in the admin interface)
changed?

Overall, we use a main model ("Employee") and several related models,
one of which is a cache with monthly sums. The main Employee model has a
field "monthly-sums-cache is valid before...", and we would like to
intelligently update this field, whenever the Employee model itself was
changed, or one of its related models.
For example, when someone corrected the date of: worked hours, taken
holidays, changes in contract, etc., we'd need to learn the change (the
date of the chance) and update the related valid-before field in the
Employee model accordingly.

(We'm primarily looking for a solution that works in the Django admin
interface, but if it works everywhere, i.e. independently from the admin
interface, that would be even better.)

I've looked into the ModelAdmin.save_model() method documented at
<https://docs.djangoproject.com/en/1.3/ref/contrib/admin/#modeladmin-methods>,
but it seems to deal only with the parent model.

By the way, a question about save_model():
How do I learn the old and new values of the fields in save_model(),
i.e. how can I know which fields have changed?

Alternatively, overriding Model.save() might be an option, but is it
safe to manipulate *and* save a *related* model instance from
Model.save()? In Model.save(), how can we learn if a field has changed,
rather than see only the new values?


I'd be very grateful for your advice!

Many thanks and best regards,
Carsten

Shawn Milochik

unread,
Aug 25, 2011, 10:22:51 AM8/25/11
to django...@googlegroups.com
Use django-celery and call the update in the save() or with a post_save
signal.

That will work under all circumstances, admin or not, and occur
asynchronously.

If you're not already using RabbitMQ or django-celery it's super easy.

Carsten Fuchs

unread,
Aug 25, 2011, 10:43:16 AM8/25/11
to django...@googlegroups.com
Dear Shawn,

Am 25.08.2011 16:22, schrieb Shawn Milochik:
> Use django-celery and call the update in the save() or with a post_save
> signal.
>
> That will work under all circumstances, admin or not, and occur
> asynchronously.

Many thanks for your quick reply, but is there a way to achieve this
with pure Django means?

That is, without dependency on django-celery (which looks a bit
oversized for the task) or another heavy-weight external package, and
synchronously?

Again my thanks and best regards,
Carsten

Shawn Milochik

unread,
Aug 25, 2011, 10:44:54 AM8/25/11
to django...@googlegroups.com
Sure. Just write your code and call it from the save() or post_save signal.

Matt Schinckel

unread,
Aug 25, 2011, 7:32:25 PM8/25/11
to django...@googlegroups.com
The advantage of using post_save or overriding save() is that it is immediate: if you then return a representation of the parent model, it will be up-to-date.

If you use django-celery (or similar) it may take some time to update.

Of course, the disadvantages is that your request has to wait for the update of the parent model to finish before it returns a response.

Matt.

Carsten Fuchs

unread,
Aug 30, 2011, 10:06:19 AM8/30/11
to django...@googlegroups.com
Hi all,

many thanks to everyone who replied!

For the records/archives, here is the solution that we eventually
implemented:

Am 25.08.2011 16:19, schrieb Carsten Fuchs:
> what is the best way to automatically update a parent model when one of
> it's related models (i.e. the "inline" models in the admin interface)
> changed?

For the related models (except for the single related model that
contains the cache (the dependent monthly sums)), overriding the save()
and delete() methods was very simple and straightforward:
The code in these function updates the "cache is valid before" member in
the main model before running the save() or delete() methods in the
super class.

For the main model itself, it turned out that overriding delete() was
never necessary, because if the main model is deleted, it's cached data
is deleted as well, no need to update the "cache is valid before" member.

Overriding save() in the main model (for cases when a change to the main
model requires an update of the cache) turned out to be not a good idea,
because it easily conflicts with the newly overridden save() methods of
the related models, whose implementation in turn calls save() of the
main model.
Instead, for the main model, we overrode save_model() in the ModelAdmin.

In summary, overriding save() for the related models and save_model() in
ModelAdmin for the main model solved the problem.

Best regards,
Carsten

--
Cafu - the open-source Game and Graphics Engine
for multiplayer, cross-platform, real-time 3D Action
Learn more at http://www.cafu.de

Reply all
Reply to author
Forward
0 new messages