How to use get_or_create in Django?
The TLDR answer
This is one of those two query one command ORM methods. It would make a query to the database with the given where clause query and if not found then it will create a new entry in the table using the default values.
It returns a tuple that has the object and a boolean field saying whether the entry was created or fetched. For example, take the example below
class Profile(models.Models):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
gender = models.CharField(max_length=1)
age = models.IntegerField()
obj, created = Profile.objects.get_or_create(
first_name='Argo',
last_name='Saha',
defaults={'gender': 'M', age=10},
)
obj
would be returning the Profile
object which would be either created or fetched from the database, and created
would be the boolean field which would be saying if the entry was created or fetched. Here defaults
is a dict that will only be used when there is not matching Profile
entry present in the database with the given first_name
and last_name
.
The Detailed Answer:
Here are the steps which take place under the hood
- Fire a query to the database to see if the entry is present with
first_name='Argo
andlast_name='Saha'
- If such entry is present the
obj
would have the entry, else a new query would be fired to create a new entry withfirst_name='Argo
andlast_name='Saha'
and any data with is supplied indefaults
Which can be written as the following code -
try:
obj = Profile.objects.get(first_name='Argo', last_name='Saha')
except Profile.DoesNotExist:
obj = Profile(first_name='Argo', last_name='Saha', age=10, gender='M')
obj.save()
The above code can be simplified using a single line of code.
obj, created = Profile.objects.get_or_create(
first_name='Argo',
last_name='Saha',
defaults={'gender': 'M', age=10},
)
However, there is a caveat which one needs to understand. Here is a note from the official documentation.
This method is atomic assuming that the database enforces uniqueness of the keyword arguments (seeunique
orunique_together
). If the fields used in the keyword arguments do not have a uniqueness constraint, concurrent calls to this method may result in multiple rows with the same parameters being inserted.
It suggests that you should be implementing a DB level check when concurrency is a concern, so that during race conditions no duplicate entries are created, which might cause a MultipleObjectsReturned
exception.
For further details, I would strongly recommend you to go through the official documentation
You can read more about update_or_create
in the other blog