In a django model custom save() method, how should you identify a new object?

I want to trigger a special action in the save() method of a Django model object when I'm saving a new record (not updating an existing record.)

Is the check for (self.id != None) necessary and sufficient to guarantee the self record is new and not being updated? Any special cases this might overlook?


Solution 1:

Alternative way to checking self.pk we can check self._state of the model

self._state.adding is True creating

self._state.adding is False updating

I got it from this page

Solution 2:

Updated: With the clarification that self._state is not a private instance variable, but named that way to avoid conflicts, checking self._state.adding is now the preferable way to check.


self.pk is None:

returns True within a new Model object, unless the object has a UUIDField as its primary_key.

The corner case you might have to worry about is whether there are uniqueness constraints on fields other than the id (e.g., secondary unique indexes on other fields). In that case, you could still have a new record in hand, but be unable to save it.

Solution 3:

Checking self.id assumes that id is the primary key for the model. A more generic way would be to use the pk shortcut.

is_new = self.pk is None

Solution 4:

The check for self.pk == None is not sufficient to determine if the object is going to be inserted or updated in the database.

The Django O/RM features an especially nasty hack which is basically to check if there is something at the PK position and if so do an UPDATE, otherwise do an INSERT (this gets optimised to an INSERT if the PK is None).

The reason why it has to do this is because you are allowed to set the PK when an object is created. Although not common where you have a sequence column for the primary key, this doesn't hold for other types of primary key field.

If you really want to know you have to do what the O/RM does and look in the database.

Of course you have a specific case in your code and for that it is quite likely that self.pk == None tells you all you need to know, but it is not a general solution.

Solution 5:

You could just connect to post_save signal which sends a "created" kwargs, if true, your object has been inserted.

http://docs.djangoproject.com/en/stable/ref/signals/#post-save