Pass existing model Instance to update_or_create callables

55 views
Skip to first unread message

James Pulec

unread,
Oct 26, 2020, 2:45:47 PM10/26/20
to Django developers (Contributions to Django itself)
Since update_or_create supports callables in the defaults dictionary, I'm wondering if it's worth considering passing the existing instance (if one is found) to those callables when resolving them.

The scenario I'm running into involves wanting to merge json data. Basically, I have a JSON field on the model that I'd like to do an update_or_create for, but in the case where there's an existing instance and I'd be performing an update, I'd like the merge the existing JSON data with the data I'm passing to my defaults.

One way I can imagine solving for this case is to pass the existing model instance to callables defined in the defaults dictionary, if an existing model instance is found.

This does feel a little gross, since you'll need to check if the passed value is None, so definitely open to other suggestion.s.

Wanted to post this here before on Trac to see if there's interest, better solutions, or any concerns.

Thanks!

Adam Johnson

unread,
Oct 26, 2020, 3:22:57 PM10/26/20
to django-d...@googlegroups.com
I think the scenario you're suggesting is just a little too complex for update_or_create. It doesn't actually fetch the updated model instance . You can instead write out what you want without too much extra code using get_or_create, ensuring there's a transaction and select_for_update() to lock the object whilst you modify it:

with transaction.atomic():
    obj, created = Model.objects.select_for_update().get_or_create(key=some_key, defaults={"json_field": fresh_json})
    if not created:
        obj.json_field = merge_json(obj.json_field, fresh_json)
        obj.save()

If you look inside update_or_create you'll see it essentially does this already. If you use the pattern frequently, you can always wrap it up in your own method.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/f44a3f50-1d01-467f-988e-8d43537a8f98n%40googlegroups.com.


--
Adam

James Pulec

unread,
Oct 28, 2020, 1:03:19 PM10/28/20
to Django developers (Contributions to Django itself)
Hey Adam,

Thanks for the clarification. I totally get that this might be a bit too complex, and maybe shouldn't wind up in update_or_create(), so I can definitely just use my own manager method. I'm a little confused by this statement, though:

"It doesn't actually fetch the updated model instance."

Isn't the return obj the model instance to be updated? From what I can tell that's exactly what's happening in the source of update_or_create() as well. Am I missing something here?

Adam Johnson

unread,
Oct 28, 2020, 1:14:26 PM10/28/20
to django-d...@googlegroups.com
Yes, it does, my bad.



--
Adam
Reply all
Reply to author
Forward
0 new messages