1

Is there a way to do the following in django's ORM?

INSERT INTO mytable
VALUES (1,2,3)
ON DUPLICATE KEY
UPDATE field=4

I'm familiar with get_or_create, which takes default values, but that doesn't update the record if there are differences in the defaults. Usually I use the following approach, but it takes two queries instead of one:

item = Item(id=1)
item.update(**fields)
item.save()

Is there another way to do this?

3 Answers 3

2

I'm familiar with get_or_create, which takes default values, but that doesn't update the record if there are differences in the defaults.

update_or_create should provide the behavior you're looking for.

Item.objects.update_or_create(
    id=1,
    defaults=fields,
)

It returns the same (object, created) tuple as get_or_create.

Note that this will still perform two queries, but only in the event the record does not already exist (as is the case with get_or_create). If that is for some reason unacceptable, you will likely be stuck writing raw SQL to handle this, which would be unfortunate in terms of readability and maintainability.

Sign up to request clarification or add additional context in comments.

1 Comment

@kungphy -- thanks for this answer. Incidentally, I also really liked your other answer (that you deleted). I'm a relatively inexperienced programmer and I was just wondering how your answer was different than my question -- it was really more a question out of curiosity than anything else. Anyways, thanks for all your help with these questions!
0

I think get_or_create() is still the answer, but only specify the pk field(s).

item, _ = Item.objects.get_or_create(id=1)
item.update(**fields)
item.save()

4 Comments

I'm not sure if you want to overwrite the special builtin _ which gives you the last returned item...
I believe that usage of _ only exists within interactive shells. In module code, _ is often used to mean "a value that I don't care about".
I remember there was another question here that was caused by the shadowing of _ in the code, which probably was also in interactive shell only as I'm unable to reproduce it now. Thanks for the tips.
The cases where you run a WSGI application view in the interactive interpreter and get your prompt back while still in the view's scope should be rather few.
0

Django 4.1 has added the support for INSERT...ON DUPLICATE KEY UPDATE query. It will update the fields in case the unique validation fails.

Example of above in a single query:

# Let's say we have an Item model with unique on key

items = [
    Item(key='foobar', value=10),
    Item(key='foobaz', value=20),
]

# this function will create 2 rows in a single SQL query
Item.objects.bulk_create(items)

# this time it will update the value for foobar
# and create new row for barbaz
# all in a single SQL query
items = [
    Item(key='foobar', value=30),
    Item(key='barbaz', value=50),
]

Item.objects.bulk_create(
    items,
    update_conflicts=True,
    update_fields=['rate']
)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.