form.has_changed always true?

1,923 views
Skip to first unread message

Alastair Campbell

unread,
Jan 6, 2010, 7:34:27 PM1/6/10
to Django users
Hi everyone,

I've been looking for a simple way to send an email when a user
updates their profile.

After some digging I found form.has_changed() which appears to fit the
bill. However, it always seems to return true, so I could end up
bombarding our elderly admin lady with lots of useless emails.

I'm using a simple model form (with a sub-set of the available
fields), rendered in the default manner, no hidden fields or anything.
If I open the page, hit save, if form.has_changed(): runs.

Is there anything else that might cause has_changed to be true?

Perhaps this is why has_changed() isn't mentioned in the documentation?

I kinda hope I'm being stupid on this one, I'd rather not get into a
long comparison function!

-Alastair

Karen Tracey

unread,
Jan 6, 2010, 9:50:56 PM1/6/10
to django...@googlegroups.com
On Wed, Jan 6, 2010 at 7:34 PM, Alastair Campbell <ala...@gmail.com> wrote:
Hi everyone,

I've been looking for a simple way to send an email when a user
updates their profile.

After some digging I found form.has_changed() which appears to fit the
bill. However, it always seems to return true, so I could end up
bombarding our elderly admin lady with lots of useless emails.

I'm using a simple model form (with a sub-set of the available
fields), rendered in the default manner, no hidden fields or anything.
If I open the page, hit save, if form.has_changed(): runs.

Is there anything else that might cause has_changed to be true?


has_changed() returns True if the bound data of the form differs from the initial data. It does work and it does not always return True.  Without specifics of the code you are using to construct your form I'm not sure why it is always seeming to return True in your case.

Karen

Margie Roginski

unread,
Jan 7, 2010, 1:12:43 AM1/7/10
to Django users
If you look at the form's _changed_data attribute, it will give you a
list of the fields that have changed. That should tell you what is
causing has_changed() to return True.

Margie

Alastair Campbell

unread,
Jan 7, 2010, 7:14:43 PM1/7/10
to django...@googlegroups.com
Hi Margie,

Thanks for the tip, when I do that, every filled-in field is returned
as changed.

I've put the model form definition and the view up here:
http://dpaste.com/142308/

Any idea what I'm doing wrong? Perhaps something to do with loading
the form with data in the first place?

Kind regards,

-Alastair

Karen Tracey

unread,
Jan 7, 2010, 8:09:16 PM1/7/10
to django...@googlegroups.com
On Thu, Jan 7, 2010 at 7:14 PM, Alastair Campbell <ala...@gmail.com> wrote:

I've put the model form definition and the view up here:
http://dpaste.com/142308/

Any idea what I'm doing wrong? Perhaps something to do with loading
the form with data in the first place?


You want to pass the instance parameter when you create the form from POST data, same as you do when you create the form initially for display.  That is where the form's initial data comes from.  When you create a form with just the POST dictionary and no instance parameter, every supplied field in the data dictionary appears to have changed since there is no initial data.

Using the instance parameter is the POST leg also allows you to simply save() the form to get the changes to the instance saved.  There is then no need to individually copy each of the fields from the form's cleaned_data dict to the model instance.  See:

http://docs.djangoproject.com/en/1.1/topics/forms/modelforms/#the-save-method

Karen

Alastair Campbell

unread,
Jan 11, 2010, 6:43:19 PM1/11/10
to django...@googlegroups.com
On Fri, Jan 8, 2010 at 1:09 AM, Karen Tracey <kmtr...@gmail.com> wrote:
> Using the instance parameter is the POST leg also allows you to simply
> save() the form to get the changes to the instance saved.  There is then no
> need to individually copy each of the fields from the form's cleaned_data
> dict to the model instance.  See:

Thanks Karen, that worked great.

I had done quite a few non-model forms, which is a more manual
process, I hadn't twigged that you save the form rather than the
model. After that, the changed form aspect works great and I can
selectively output the changed data.

Thanks for the help,

-Alastair

ducu

unread,
Feb 25, 2010, 3:03:25 PM2/25/10
to Django users
Btw, has_changed() doesn't seem to work on non-model forms, does it?

On Jan 12, 12:43 am, Alastair Campbell <ala...@gmail.com> wrote:

Karen Tracey

unread,
Feb 25, 2010, 3:57:16 PM2/25/10
to django...@googlegroups.com
On Thu, Feb 25, 2010 at 3:03 PM, ducu <alexandr...@gmail.com> wrote:
Btw, has_changed() doesn't seem to work on non-model forms, does it?


Yes, it does:

>>> from django import forms
>>> class AForm(forms.Form):
...     x = forms.IntegerField()
...
>>> af = AForm({'x': u'1'}, initial={'x': 1})
>>> af.has_changed()
False
>>> af = AForm({'x': u'1'}, initial={'x': 0})
>>> af.has_changed()
True

Karen

Jirka Vejrazka

unread,
Feb 26, 2010, 6:19:11 AM2/26/10
to django...@googlegroups.com
Hi,

if I digress from the has_changed() problem, you mentioned you
wanted to send email after a user profile has changed. Assuming that
the profile is a model in the database, you might consider tying your
logic to the model rather than the form.

The post_save signal tied to the profile-related model might just do
the trick for you.

Cheers

Jirka

Reply all
Reply to author
Forward
0 new messages