Django pre_save signal: check if instance is created not updated, does kwargs['created'] (still) exist?
Asked Answered
T

7

42

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.

Tutankhamen answered 31/8, 2010 at 9:9 Comment(4)
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.Latten
@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?Tutankhamen
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: code.djangoproject.com/browser/django/trunk/django/db/models/…Latten
Thanks for your hint! I've included it in my code and will keep this in mind for future projects.Tutankhamen
A
31

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.

Artilleryman answered 31/8, 2010 at 9:20 Comment(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!Tutankhamen
exactly as Manoj said, in this case you could use the instance.pk and verify if that row exists, in that case is an updateAccroach
S
70

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

Smack answered 26/8, 2012 at 17:32 Comment(3)
@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.Dipteral
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.Nictitate
this is preferred over using a private method or attribute.Hurleigh
A
31

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.

Artilleryman answered 31/8, 2010 at 9:20 Comment(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!Tutankhamen
exactly as Manoj said, in this case you could use the instance.pk and verify if that row exists, in that case is an updateAccroach
D
27

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://mcmap.net/q/391215/-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?

Dorran answered 29/7, 2015 at 9:22 Comment(0)
P
13

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.

Pennyweight answered 21/4, 2020 at 21:46 Comment(0)
B
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.

Bewilder answered 3/10, 2015 at 4:32 Comment(0)
D
2

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

Delcine answered 22/12, 2022 at 10:2 Comment(1)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From ReviewSometimes
G
0

You can try this.

@receiver(pre_save, sender=User)
def user(instance, *args, **kwargs):
    if instance.id != None:
Giacinta answered 20/8, 2022 at 9:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.