106

I have a Django application that reads data from a web API and puts it in a database.
Is there a way to create a new object from a mode but prevent the duplicate exception if the object already exists?

In other words, is there a way to save an object, but to just do nothing if it already exists?

Paolo Forgia
  • 6,572
  • 8
  • 46
  • 58
user1094786
  • 6,402
  • 7
  • 29
  • 42

4 Answers4

202

Model.objects.get_or_create()

second
  • 28,029
  • 7
  • 75
  • 76
  • 12
    making it a link to the docs adds some chars (and makes it a better answer i guess) – second Feb 03 '13 at 09:39
  • 5
    This seems to make 2 queries. If I only want to save the object in case it doesn't exists, is there a way with only 1 query? I guess catching `IntegrityError` cause current transaction to abort and is not sufficient. – Amir Ali Akbari Jan 24 '15 at 11:13
  • you can catch the integrity error if you add a savepoint, e.g. using `transaction.atomic` (make sure you catch _outside_ the `atomic` block, i.e. `try: with acomic: create; except IntegrityError`. It's also tricky to make sure you don't catch _other_ integrity errors than the one you intend to – second Nov 27 '16 at 08:47
  • If you are able to catch the `IntegrityError`, my testing shows that it cuts the execution time nearly in half when the record exists compared to `get_or_create()`. – Ron Sep 02 '18 at 06:27
50

In Django 1.7, you can also do:

Model.objects.update_or_create()

Benoit Blanchon
  • 13,364
  • 4
  • 73
  • 81
6

It can be achieved using Model.objects.get_or_create()

Example

obj, created = Person.objects.get_or_create(
    first_name='John',
    last_name='Lennon',
    defaults={'birthday': date(1940, 10, 9)},
)

Any keyword arguments(here first_name and last_name) passed to get_or_create() — except an optional one called defaults — will be used to query in database(find the object) in database.

It returns a tuple, if an object is found, get_or_create() returns a tuple of that object and False.

Note: Same thing can also be achieved using try except statements
Example:

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
    obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
    obj.save()
Abhishek Pratap Singh
  • 613
  • 3
  • 11
  • 18
3

Looks like in newer versions of Django the save() function does an UPDATE or INSERT by default. See here.

crperez
  • 130
  • 1
  • 10
  • looks like it should choose well automatically, however in my db it is currently duplicating entries every time I run my script to populate the db. – martin-martin Aug 12 '18 at 07:39
  • 1
    the save() method checks if the PK of the model has a value. The Author would have to query the DB in order to get the model instance with the correct PK in order to use this technique. The sole use of save() does not do the magic. – chickahoona Apr 27 '19 at 09:24