in my model, how can I tell when I'm saving a new item

345 views
Skip to first unread message

webcomm

unread,
Jul 25, 2011, 3:03:09 PM7/25/11
to Django users
I want to override the save method in one of my models. How do I know
if I'm calling save on a newly created item or on one that is already
in the database? How to make that distinction in my save method?

Thanks,
Ryan

Javier Guerra Giraldez

unread,
Jul 25, 2011, 3:07:38 PM7/25/11
to django...@googlegroups.com

if it has an id, it's not new

--
Javier

Dmitry Pisklov

unread,
Jul 25, 2011, 3:08:56 PM7/25/11
to django...@googlegroups.com
Have a look at this doc:

Basically, it says, that given you're not going to assign primary key prior to saving your object to DB, you may rely on PK field's value, e.g. if it's None - it's new model, otherwise it's existing object.

webcomm

unread,
Jul 25, 2011, 3:50:54 PM7/25/11
to Django users
I'm still learning python, so have to ask about how this would be
done. Something like the following?

try:
self.id
except NameError:
# run this code if it is a new item
else:
# run this code if this is a previously saved item

More generally, what do you think of this statement: "If there are
any cases where you don't absolutely know if a variable is defined,
you have a broken design."
That's at http://stackoverflow.com/questions/1592565/determine-if-variable-is-defined-in-python/1592578#1592578
I've worked on many scripts where it wasn't possible to know if a
variable is defined, so I'm surprised to see someone vehemently argue
that this should never happen.

Javier Guerra Giraldez

unread,
Jul 25, 2011, 3:57:20 PM7/25/11
to django...@googlegroups.com
On Mon, Jul 25, 2011 at 2:50 PM, webcomm <rya...@gmail.com> wrote:
> try:
>  self.id
> except NameError:
>  # run this code if it is a new item
> else:
>  # run this code if this is a previously saved item

works, but it's nicer to use "if hasattr(obj,field): ...."


> More generally, what do you think of this statement:  "If there are
> any cases where you don't absolutely know if a variable is defined,
> you have a broken design."

it's generally reasonable; but in this case it's not about an
undefined variable; it's an attribute. Since the ID value is defined
only by the database, it's reasonable to leave it undefined until it's
defined :-)

--
Javier

webcomm

unread,
Jul 25, 2011, 6:01:27 PM7/25/11
to Django users
On Jul 25, 3:57 pm, Javier Guerra Giraldez <jav...@guerrag.com> wrote:
> On Mon, Jul 25, 2011 at 2:50 PM, webcomm <rya...@gmail.com> wrote:
> > try:
> >  self.id
> > except NameError:
> >  # run this code if it is a new item
> > else:
> >  # run this code if this is a previously saved item
>
> works, but it's nicer to use "if hasattr(obj,field): ...."

Thanks. Any idea why the following isn't working in my News class?
The processing doesn't get to that exit call, even if it's a new item.

def save(self, *args, **kwargs):
if not hasattr(self,'id'):
import sys
sys.exit('must be a new item')
super(News, self).save(*args, **kwargs)

webcomm

unread,
Jul 25, 2011, 7:05:04 PM7/25/11
to Django users
> Thanks.  Any idea why the following isn't working in my News class?
> The processing doesn't get to that exit call, even if it's a new item.
>
>     def save(self, *args, **kwargs):
>         if not hasattr(self,'id'):
>             import sys
>             sys.exit('must be a new item')
>         super(News, self).save(*args, **kwargs)


hasattr doesn't work in this situation, or I'm not using it right. In
any case, the following works:

def save(self, *args, **kwargs):
if not self.id:
import sys
sys.exit('a new item')
super(News, self).save(*args, **kwargs)

Ian Clelland

unread,
Jul 25, 2011, 7:35:45 PM7/25/11
to django...@googlegroups.com
webcomm,

Whether you have defined an 'id' field in your model, or let Django do it for you, each of your objects will "have" an id attribute, and so hasattr(my_object, 'id') will always be true. The *value* of that attribute might be None, though, and that's why works when you simply test self.id, like you did above.

hasattr is generally useful in a function when you are not sure what kind of object has been passed in, or if you want to tell whether an object has been augmented with a specific attribute. When you know that the attribute exists, then you can use getattr(self, "id"), or just access the attribute directly (like "self.id")


That being said, though, there are situations where you can't rely on an id being a guarantee that the object already exists. Like any field, it is possible to specify the id when creating an object in memory, like this:

new_object = News(id=1, headline="Breaking news!", content="Database broken!")
new_object.save()

This object will have an id set when the save() method checks for it, and so any code that you needed to run for new items will be skipped.

In fact, this is exactly what happens when you load fixtures, either with "manage.py loaddata", or by using fixtures in tests.

If there is code that absolutely has to run when a new object is created, (or code that needs to run on update, but absolutely cannot run on new objects before insertion), then you may be better off using a post-save signal handler, and checking the "created" argument that gets passed to it.


--
Regards,
Ian Clelland
<clel...@gmail.com>
Reply all
Reply to author
Forward
0 new messages