246π
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.
360π
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
- [Django]-Django Model() vs Model.objects.create()
- [Django]-Import data from excel spreadsheet to django model
- [Django]-How to add superuser in Django from fixture
53π
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
- [Django]-Stack trace from manage.py runserver not appearing
- [Django]-Why does django run everything twice?
- [Django]-Why is factory_boy superior to using the ORM directly in tests?
43π
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.
- [Django]-Access web server on VirtualBox/Vagrant machine from host browser?
- [Django]-Django: how save bytes object to models.FileField?
- [Django]-Sending HTML email in django
12π
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
- [Django]-How to check if a user is logged in (how to properly use user.is_authenticated)?
- [Django]-How to get the current URL within a Django template?
- [Django]-Ignoring Django Migrations in pyproject.toml file for Black formatter
7π
Check for self.id
and the force_insert
flag.
if not self.pk or kwargs.get('force_insert', False):
self.created = True
# call save method.
super(self.__class__, self).save(*args, **kwargs)
#Do all your post save actions in the if block.
if getattr(self, 'created', False):
# So something
# Do something else
This is handy because your newly created object(self) has it pk
value
- [Django]-No handlers could be found for logger
- [Django]-Django β Website Home Page
- [Django]-Data Mining in a Django/Postgres application
7π
Iβm very late to this conversation, but I ran into a problem with the self.pk being populated when it has a default value associated with it.
The way I got around this is adding a date_created field to the model
date_created = models.DateTimeField(auto_now_add=True)
From here you can go
created = self.date_created is None
- [Django]-How to check if ManyToMany field is not empty?
- [Django]-Using Cloudfront with Django S3Boto
- [Django]-Django: How to get related objects of a queryset?
6π
For a solution that also works even when you have a UUIDField
as a primary key (which as others have noted isnβt None
if you just override save
), you can plug into Djangoβs post_save signal. Add this to your models.py:
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=MyModel)
def mymodel_saved(sender, instance, created, **kwargs):
if created:
# do extra work on your instance, e.g.
# instance.generate_avatar()
# instance.send_email_notification()
pass
This callback will block the save
method, so you can do things like trigger notifications or update the model further before your response is sent back over the wire, whether youβre using forms or the Django REST framework for AJAX calls. Of course, use responsibly and offload heavy tasks to a job queue instead of keeping your users waiting π
- [Django]-Django-nonrel + Django-registration problem: unexpected keyword argument 'uidb36' when resetting password
- [Django]-Django MultiValueDictKeyError error, how do I deal with it
- [Django]-Django Multiple Authentication Backend for one project
- [Django]-Django-Forms with json fields
- [Django]-In a Django form, how do I make a field readonly (or disabled) so that it cannot be edited?
- [Django]-How to monkey patch Django?
1π
It is the common way to do so.
the id will be given while saved first time to the db
- [Django]-How do I create a slug in Django?
- [Django]-Django composite unique on multiple model fields
- [Django]-Annotate a queryset with the average date difference? (django)
1π
> def save_model(self, request, obj, form, change):
> if form.instance._state.adding:
> form.instance.author = request.user
> super().save_model(request, obj, form, change)
> else:
> obj.updated_by = request.user.username
>
> super().save_model(request, obj, form, change)
- [Django]-Use Python standard logging in Celery
- [Django]-PHP Frameworks (CodeIgniter, Yii, CakePHP) vs. Django
- [Django]-How to change site title, site header and index title in Django Admin?
0π
Would this work for all the above scenarios?
if self.pk is not None and <ModelName>.objects.filter(pk=self.pk).exists():
...
- [Django]-Django rest framework, use different serializers in the same ModelViewSet
- [Django]-Multiple Database Config in Django 1.2
- [Django]-Django β how to visualize signals and save overrides?
0π
A more modern approach For Python3.8 and above using the walrus operator. (if you want to save some lines of code)
def save(self, *args, **kwargs):
if is_new_obj := self._state.adding:
# Do some Pre_Save processing for new objects to be created
super().save(*args, **kwargs)
if is_new_obj:
# Do some Post_Save processing for newly created objects
- [Django]-How does one make logging color in Django/Google App Engine?
- [Django]-Django multiple template inheritance β is this the right style?
- [Django]-How to update an existing Conda environment with a .yml file
-1π
In python 3 and django 3 this is whatβs working in my project:
def save_model(self, request, obj, form, change):
if not change:
#put your code here when adding a new object.
- [Django]-How to put comments in Django templates?
- [Django]-Separating form input and model validation in Django?
- [Django]-Django Admin Form for Many to many relationship
-3π
To know whether you are updating or inserting the object (data), use self.instance.fieldname
in your form. Define a clean function in your form and check whether the current value entry is same as the previous, if not then you are updating it.
self.instance
and self.instance.fieldname
compare with the new value
- [Django]-Django development server reload takes too long
- [Django]-Django set default form values
- [Django]-Visual Editor for Django Templates?