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 and last_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 with first_name='Argo and last_name='Saha' and any data with is supplied in defaults

Which can be written as the following code -

try:
    obj = Profile.objects.get(first_name='Argo', last_name='Saha')
except Person.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 (see unique or unique_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

QuerySet API reference | Django documentation | Django

You can read more about update_or_create in the other blog

When to use update_or_create in Django?
The TLDR answer:If you have used get_or_create[https://thetldr.tech/how-to-use-get-or-create-in-django/] you must have had thethought of if there is any Django ORM that could update_or_create. Well, Djangohas the exact implementation which can either update the db object if present,else it woul…