304

I'm trying to use get_or_create() for some fields in my forms, but I'm getting a 500 error when I try to do so.

One of the lines looks like this:

customer.source = Source.objects.get_or_create(name="Website")

The error I get for the above code is:

Cannot assign "(<Source: Website>, False)": "Customer.source" must be a "Source" instance.

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
Stephen
  • 5,959
  • 10
  • 33
  • 43

8 Answers8

496

From the documentation get_or_create:

# get_or_create() a person with similar first names.

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

# get_or_create() didn't have to create an object.
>>> created
False

Explanation: Fields to be evaluated for similarity, have to be mentioned outside defaults. Rest of the fields have to be included in defaults. In case CREATE event occurs, all the fields are taken into consideration.

It looks like you need to be returning into a tuple, instead of a single variable, do like this:

customer.source,created = Source.objects.get_or_create(name="Website")
Rakmo
  • 1,926
  • 3
  • 19
  • 37
Astra
  • 10,735
  • 3
  • 37
  • 41
  • 9
    FYI created is a boolean. True if created, False if it is fetched – Josh Oct 04 '18 at 08:45
  • 5
    A additional `save()` is redundant? – zypro Dec 17 '19 at 10:56
  • 2
    @zypro It's like `create()`, create object and save it all in one step and doesn't need any `save()` – Amin Mir Jun 19 '20 at 06:05
  • 2
    NOTE: As of Django 3.2, any statement passed in `defaults` are evaluated even if a new object is not created. I ended up writing try catch statement whenever `create` needs a complex statement to execute. – Iqbal Jul 26 '21 at 17:03
  • What does the p in "p, created = Person..." stand for? What's the purpose? – alkadelik Mar 22 '23 at 21:31
  • @alkadelik, the p should be the object that has been fetched or newly created via the ORM – Chilusoft Jul 13 '23 at 09:57
41

get_or_create returns a tuple.

customer.source, created = Source.objects.get_or_create(name="Website")
Dominic Rodger
  • 97,747
  • 36
  • 197
  • 212
Tobu
  • 24,771
  • 4
  • 91
  • 98
  • 17
    Or, if you don't care about the boolean flag: `customer.source = Source.objects.get_or_create(name="Website")[0]` – mipadi Dec 21 '09 at 16:57
  • 24
    @mipadi I'd prefer `customer.source, _ = Source.objects.get_or_create(name="Website")`, as it makes the fact that a tuple was returned more obvious, helping avoid future bugs. – Solomon Ucko Apr 04 '19 at 02:32
32

get_or_create() returns a tuple:

customer.source, created  = Source.objects.get_or_create(name="Website")
  • created has a boolean value, is created or not.

  • customer.source has an object of get_or_create() method.

daaawx
  • 3,273
  • 2
  • 17
  • 16
Tushar Patil
  • 1,419
  • 1
  • 18
  • 21
22

Following @Tobu answer and @mipadi comment, in a more pythonic way, if not interested in the created flag, I would use:

customer.source, _ = Source.objects.get_or_create(name="Website")
jbondia
  • 253
  • 2
  • 7
7

The issue you are encountering is a documented feature of get_or_create.

When using keyword arguments other than "defaults" the return value of get_or_create is an instance. That's why it is showing you the parens in the return value.

you could use customer.source = Source.objects.get_or_create(name="Website")[0] to get the correct value.

Here is a link for the documentation: http://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create-kwargs

Jonas Kölker
  • 7,680
  • 3
  • 44
  • 51
wlashell
  • 888
  • 4
  • 9
1

get_or_create method would actually return a tuple.

The trick with the get_or_create method is that it actually returns a tuple of (object, created). The first element is an instance of the model you are trying to retrieve and the second is a boolean flag to tell if the instance was created or not. True means the instance was created by the get_or_create method and False means it was retrieved from the database

So you can do something like to get the source instance

 ```   customer.source = Source.objects.get_or_create(name="Website")[0]
 ```
1

get_or_create() returns the tuple which contains 2 values and the 1st value is an object and the 2nd value is the boolean value which indicates that a new object is created or not as shown below:

 # 1st   # 2nd
(object, boolean)

So, if you want both an object and a boolean value, put one more variable created after customer.source as shown below:

                 # Here
customer.source, created = Source.objects.get_or_create(name="Website")
# object         # boolean

And, if you want only an object without a boolean value, put [0] just after get_or_create() as shown below:

                                                       # Here ↓↓↓
customer.source = Source.objects.get_or_create(name="Website")[0]
# object

And, if you want only a boolean value without an object put [1] just after get_or_create() as shown below:

                                               # Here ↓↓↓
created = Source.objects.get_or_create(name="Website")[1]
# boolean
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
0

Important warning.

you should take care of the following before using the get_or_create , https://docs.djangoproject.com/en/4.0/ref/models/querysets/. .... Warning

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.

alfonsoolavarria
  • 1,141
  • 11
  • 11