ModelAdmin with inlines: How to learn if/what has changed before the models are saved?

715 views
Skip to first unread message

Carsten Fuchs

unread,
Dec 18, 2014, 12:20:34 PM12/18/14
to django...@googlegroups.com
Hi fellow Django developers,

using a model with several related models, for the Django Admin I have a
ModelAdmin that uses several InlineModelAdmin objects, very much as in
the example at
<https://docs.djangoproject.com/en/1.7/ref/contrib/admin/#inlinemodeladmin-objects>.

All works well, but when the user clicks the "Save" button in the change
view, I would like to find out if anything has changed in the parent
model or the related (inline) models, and depending on the result,
update one of the parent model's fields before it is saved.

Can you please tell me how can this be achieved?


In more detail, having read all of
https://docs.djangoproject.com/en/1.7/ref/contrib/admin/ and thinking
that I have understood most of it, the ModelAdmin methods

save_model()
save_formset()
save_related()

seem to be the right approach to my problem, but are a complete mystery
to me: How are the related to each other, and what is their purpose?

The documentation of all three begins with "The save_* method is given
the HttpRequest, ...", but what follows it too sparse for my still
limited Django knowledge, and unfortunately I cannot see yet the bigger
picture about them, or how to proceed from there.

Could someone please explain how these methods work, when they are
called, etc.?


A huge thanks in advance and best regards,
Carsten

Collin Anderson

unread,
Dec 19, 2014, 6:18:09 PM12/19/14
to django...@googlegroups.com
Hi Carsten,

save_model() happens first, then save_related() which calls save_formset() on each formset.

It might end up being easier to save the parent model _again_, instead of doing something before it's saved.

_has_changed() / has_changed() may come in handy in your case.

Collin

Alex Haylock

unread,
Dec 20, 2014, 4:50:06 PM12/20/14
to django...@googlegroups.com
On 18/12/14 17:19, Carsten Fuchs wrote:
> I would like to find out if anything has changed in the parent
> model or the related (inline) models, and depending on the result,
> update one of the parent model's fields before it is saved.
>
> Can you please tell me how can this be achieved?


Take a look at the Django signal dispatcher:
https://docs.djangoproject.com/en/dev/topics/signals/

Specifically, the 'update_fields' argument passed to the 'pre_save'
signal should provide what you need:

https://docs.djangoproject.com/en/dev/ref/signals/#django.db.models.signals.pre_save

Regards,

Alex.

Carsten Fuchs

unread,
Dec 22, 2014, 12:34:20 PM12/22/14
to django...@googlegroups.com
Hi Collin,

Am 20.12.2014 um 00:18 schrieb Collin Anderson:
> save_model() happens first, then save_related() which
> calls save_formset() on each formset.
>
> It might end up being easier to save the parent model _again_, instead
> of doing something before it's saved.

Thank you very much for your reply, that helped a lot!

> _has_changed() / has_changed() may come in handy in your case.
> https://docs.djangoproject.com/en/dev/ref/forms/fields/#has-changed

In Django 1.7, it seems that _has_changed() takes several parameters
that I had not readily available, so I eventually looked this up in the
Django 1.7 source code (django/forms/forms.py), and now instead of, for
example (probably valid Django 1.8 code):

if form.fields['birthday'].has_changed(): ...

with Django 1.7 I use:

if "birthday" in form.changed_data: ...

which works very well!

Thanks again for your help!

:-)

Best regards,
Carsten

Carsten Fuchs

unread,
Dec 22, 2014, 12:44:43 PM12/22/14
to django...@googlegroups.com
Hi Alex,

Am 20.12.2014 um 22:47 schrieb Alex Haylock:
> Take a look at the Django signal dispatcher:
> https://docs.djangoproject.com/en/dev/topics/signals/
>
> Specifically, the 'update_fields' argument passed to the 'pre_save'
> signal should provide what you need:
>
> https://docs.djangoproject.com/en/dev/ref/signals/#django.db.models.signals.pre_save

Many thanks for your reply!

While I seem to understand signals generally, I followed Collin's
suggestion, because the ModelAdmin class already has so many readily
available customization callbacks, so that this eventually looked a bit
more straightforward to me.

Also, the big question that occurred to me when I (re-)read the signals
documentation that you linked above was this description for the
`update_fields` argument:
“The set of fields to update explicitly specified in the save()
method. None if this argument was not used in the save() call.“

To be honest, I did not fully set it up to try it out, but in the
ModelAdmin source I saw that the model's save() method is plainly
called, without any explicit parameters. This would have rendered the
`update_fields` useless, and left me with no way to figure out what has
changed in the model when the pre_save signal is received, right?

Best regards,
Carsten

Reply all
Reply to author
Forward
0 new messages