Everything to Know About get_or_create() and update_or_create() in Django

Learn about the `get_or_create()` and `get_or_update()` convenience methods and how to use them in Django

Picture of Nsikak Imoh, author of Macsika Blog
A blank white background with the text everything to Know About get_or_create() and update_or_create() in Django
A blank white background with the text everything to Know About get_or_create() and update_or_create() in Django

This post is part of the tutorial series titled Learn to Use Django with FastAPI Frameworks

Table of Content

Django is flexible with how to create, update, and get entries in the database.

In addition to having single methods like the get(), update(), and create(), Django provides convenient methods for combining the process of creating, updating, and getting the created object in a single operation.

In this post, you will learn about the get_or_create() and get_or_update() convenience methods and how to use them in Django.

What is get_or_create() in Django

The get_or_create() is a convenience method in Django for looking up an object using a set of parameters or creating the object using those sets of parameters if it does not exist.

Here's the logic of what you will typically implement without the get_or_create() method.

try:
	author = Author.objects.get(name='Archangel Macsika')
except DoesNotExist:
	author = Author(name='Archangel Macsika') author.save() 

# Do something with author
Highlighted code sample.

What is update_or_create() in Django

The update_or_create() is a convenience method in Django for updating an existing object in the database using the provided parameters or creating the object using those sets of parameters if the parameter does not match any existing object in the database.

Here's the logic of what you will typically implement without the update_or_create() method.

defaults = {'name': 'Nsikak Imoh'}
try:
    author = Author.objects.get(name='Archangel Macsika')
    for key, value in defaults.items():
        setattr(author, key, value)
    author.save()
except Author.DoesNotExist:
    new_values = {'name': 'Archangel Macsika'}
    new_values.update(defaults)
    obj = Person(**new_values)
    obj.save()
Highlighted code sample.

get_or_create() vs update_or_create() in Django

In Django, get_or_create() vs update_or_create() is similar because they both act as shortcuts for running two separate query operations in one line, and both return a tuple of two elements, where the first element is the object, and the second element is a boolean indicating if there was a created operation or not.

The difference is that the get_or_create() method in Django performs a get() operation on the database objects using the parameters and if it does not exist, it performs a create() operation while the update_or_create() runs an update() operation on the database objects using the provided parameters and if it does not exist, it performs a create() operation.

How to Use get_or_create() in Django

Let's use the model definition below for our demo:

from django.db import models

class Author(models.Model):
    first_name = models.CharField(max_length=512)
    last_name = models.CharField(max_length=512)

class Post(models.Model):
    title = models.CharField(max_length=512)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
Highlighted code sample.

The get_or_create() in Django takes the form:

get_or_create(defaults=None, **kwargs) # for synchronous operations
aget_or_create`(defaults=None, **kwargs) # for asynchronous operations
Highlighted code sample.

Where defaults define object fields that are saved into the database if an object doesn't exist and kwargs define fields used in the lookup for the get method, and if defaults are not defined, the same fields are used to create the object.

To create a new author, we can run the operation as:

Author.objects.get_or_create(first_name="Archangel", last_name="Macsika")
Highlighted code sample.

In the result below, the first element of the tuple is the object and since this is a new operation that does not exist in the database, it returns True flag for created.

What happens is that it first tries to get the object using the provided parameters and if it does not exist, it creates the object using the provided parameters, and then performs the get operation again.

(<Author: Author object  (1)>, True)
Highlighted code sample.

If we run the operation for the second time, we will get the same object and the created flag is False.

This is because it simply performs the get operation and since an object is returned, there's no need of running the create operation.

(<Author: Author object  (1)>, False)
Highlighted code sample.

We can assign this operation to a single variable and the variable becomes a tuple:

author = Author.objects.get_or_create(first_name="Archangel", last_name="Macsika")
Highlighted code sample.

To access the object, you access the first element of the tuple using author[0] and the created flag is accessible using author[1].

More still, python provides a way to get unpack a tuple using multiple variables, so you can do this:

author, is_created = Author.objects.get_or_create(first_name="Archangel", last_name="Macsika")
Highlighted code sample.

The object is stored as author and the created flag is accessible using is_created.

You can also have a complex query with get_or_create() using filters and Q objects

author, is_created = Author.objects.filter(
    Q(name='Nsikak Imoh') | Q(name='Archangel Macsika')
).get_or_create(name='Archangel Macsika')
Highlighted code sample.

This query will try to find either 'Nsikak Imoh' or 'Archangel Macsika', if it doesn't find either it will create 'Archangel Macsika'.

Note: If get_or_create() finds multiple objects it will raise a MultipleObjectsReturned exception

How to Use get_or_create() with Many to Many Fields

Here's how you can use Django get_or_create() with ManyToMany fields using the sample model:

class Author(models.Model):
    name = models.CharField(max_length=255, unique=True)

class Book(models.Model):
    authors = models.ManyToManyField(Author)
    title = models.CharField(max_length=255)
Highlighted code sample.

Then run the method:

post = Post.objects.get(title='Django convenience methods')
author, created = book.authors.get_or_create(name='Archangel Macsika')
Highlighted code sample.

This will get or create author 'Archangel Macsika' for the post 'Django convenience methods'.

How to Use update_or_create() in Django

The update_or_create() method has an implementation similar to the get_or_create() method. We continue with the model definition above for our demo.

The update_or_create() in Django takes the form:

update_or_create(defaults=None, **kwargs) # for synchronous operations
aupdate_or_create`(defaults=None, **kwargs) # for asynchronous operations
Highlighted code sample.

Where defaults define object fields that are saved into the database if an object doesn't exist and kwargs define fields used in the lookup for the get method, and they subsequently become the fields that will be updated, and if defaults are not defined, the same fields are used to create the object.

To create a new author, we can run the operation as:

Author.objects.update_or_create(first_name="Archangel", last_name="Macsika")
Highlighted code sample.

In the result below, the first element of the tuple is the object and since this is a new operation that does not exist in the database, it returns True flag for created.

What happens is that it first tries to get the object using the provided parameters if it exists, it runs the update operation using the provided keyword arguments. If it does not exist, it creates the object using the provided parameters, and then performs the get operation again.

(<Author: Author object  (1)>, True)
Highlighted code sample.

If we run the operation for the second time, we will get the same object and the created flag is False.

This is because, it simply performs the get and update operation and since an object is returned, there's no need of running the create operation.

(<Author: Author object  (1)>, False)
Highlighted code sample.

We can assign this operation to a single variable and the variable becomes a tuple:

author = Author.objects.update_or_create(first_name="Archangel", last_name="Macsika")
Highlighted code sample.

To access the object, you access the first element of the tuple using author[0] and the created flag is accessible using author[1].

More still, python provides a way to get unpack a tuple using multiple variables, so you can do this:

author, is_created = Author.objects.update_or_create(first_name="Archangel", last_name="Macsika")
Highlighted code sample.

The object is stored as author and the created flag is accessible using is_created.

Note: If update_or_create() finds multiple objects it will raise a MultipleObjectsReturned exception

The Uniqueness Constraint Issue With get_or_create() in Django

The get_or_create() method is prone to a race-condition, which can result in multiple rows being inserted simultaneously if uniqueness is not enforced at the database level.

Since get_or_create() first try to get() and if it cannot, it will try to create the object inside a transaction, and if that operation fails with an IntegrityError, it will then grab the object and return it.

This means that in a potential race condition, if both processes got past the first operation and are trying to create the object, and there is no uniqueness constraint, they will both create the object.

That's why, to guarantee an atomic transaction, there has to be a uniqueness constraint on the fields you are querying enforced at the database level.

class Author(models.Model):
    ...
    
    class Meta:
        unique_together = ('first_name', 'last_name')
Highlighted code sample.

Wrap Off

Django is flexible with how to create, update, and get entries in the database. You can use the get_or_create() and update_or_create() to carry out query operations in a single operation.

The methods get_or_create() and update_or_create() are similar because they both are shortcuts for running two separate query operations in one line and both returns a tuple of two elements, where the first element is the object, and the second element is a boolean indicating if there was a created operation or not.

They differ in how both carry out their operation.

If you learned from this tutorial, or it helped you in any way, please consider sharing and subscribing to our newsletter.

Please share this post and for more insightful posts on business, technology, engineering, history, and marketing, subscribe to our newsletter.

Get the Complete Code of Django and FastAPI Combo Tutorials on Github.

Connect with me.

Need an engineer on your team to grease an idea, build a great product, grow a business or just sip tea and share a laugh?