38

I am using Django's pre_save signal to implement auto_now_add. There is a lot of discussion on the internet on why you should or shouldn't implement it yourself. I do not appreciate comments on this. Neither on whether I should be rewriting the save function (I have a lot of models that use auto_now_add so using signals makes sense).

My question is:
I would like to check if the instance is created or updated. According to some sources on the internet this can be done by testing if kwargs['created'] is True. However 'created' does not appear in my kwargs even though the instance is newly created. I was just wondering if it has ever existed or that it has disappeared magically. I know I could also test if kwargs['instance'].id is set (this in fact works for me), but I'd like to know if kwargs['created'] still exists.

Heyl1
  • 2,437
  • 3
  • 24
  • 31
  • 1
    One thing to keep in mind, is that if the instance id/pk is set that does not necessarily mean that the object exists in the database. A common example would be if those instances are loaded from __fixtures__. – Botond Béres Aug 31 '10 at 13:10
  • @Botondus: Is there a better way (to avoid the problem you're mentioning) to check whether the instance is being newly created or whether it is being updated during pre_save? – Heyl1 Aug 31 '10 at 13:37
  • Yes, if PK is set you actually have to query the database to decide for sure if an instance is already created or not. Something like: MyModel.objects.filter(pk=pk_val).exists() It's actually implemented in a similar way in Django's internals: http://code.djangoproject.com/browser/django/trunk/django/db/models/base.py#L493 – Botond Béres Aug 31 '10 at 16:24
  • Thanks for your hint! I've included it in my code and will keep this in mind for future projects. – Heyl1 Sep 01 '10 at 12:14

7 Answers7

66

Primary key attribute usually assigned by the database when the instance saved first time. So you can use something like if instance.pk is None

Radagast
  • 5,798
  • 3
  • 22
  • 18
  • @phasetwenty You can lock table and additionaly check if a record with such natural key exists. Or use surrogate key as primary and natural as secondary. – Gill Bates Jul 04 '14 at 18:26
  • In Django, everything has a primary key, so this is a very standard way of checking if the instance has ever been saved. Even a natural-keyed model will have a pk that you can check to determine if the instance has been saved. – Bobort Sep 27 '18 at 14:34
  • this is preferred over using a private method or attribute. – binarymason May 20 '21 at 15:31
28

According to the latest Django documentation, pre_save does NOT send a created argument. Post_save however does. I could not find any reference of the signal sending created since version 1.0.

Manoj Govindan
  • 72,339
  • 21
  • 134
  • 141
  • 2
    Thank you very much for your reply. I must have misread the sources and assumed that 'created' also appeared in the pre_save signal. It actually makes sense when you think about it. Thanks for clearing this up for me! – Heyl1 Aug 31 '10 at 09:45
  • exactly as Manoj said, in this case you could use the `instance.pk` and verify if that row exists, in that case is an update – Darkaico Jan 18 '21 at 15:03
24

I am not sure if this is the recommended way but @Radagast's method didnt work for me(not sure if its because I use custom Pk's).

I tried the following(not sure if this is the best way):

@receiver(pre_save, sender=YourModelName, weak=False, )
def presave_payment_model_check(sender, instance=None, created=False, **kwargs):
    #Reference: https://stackoverflow.com/questions/11561722/django-what-is-the-role-of-modelstate
    if instance._state.adding:
        # we would need to create the object
        print "Creating an object"
    else:
        #we are updating the object
        print "Updating an object"
    

Reference: Django : What is the role of ModelState?

Pranaysharma
  • 537
  • 6
  • 13
11

You can easily check if an instance is created or updated in pre_save in this way:

@receiver(pre_save, sender=MyModel)
def pre_save_user(sender, instance, **kwargs): 
    if instance._state.adding:
        print ('Instance created!')
    else:
        print ('Instance updated!')

Tested with Django 3.0.

Marco Ferrantini
  • 381
  • 2
  • 10
4

Using instance._state.adding is the most logical approach, as you will be able to tell the model state exists or is new, regardless whether the primary key as been assigned or not.

Timothy Mugayi
  • 1,449
  • 17
  • 11
2

When pk is a custom uuid field, instance.pk will also have value on create.

  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/33473437) – コリン Dec 25 '22 at 14:44
0

You can try this.

@receiver(pre_save, sender=User)
def user(instance, *args, **kwargs):
    if instance.id != None:
Sammrafi
  • 399
  • 4
  • 8