#35793: Add support for atomic upserts -------------------------------------+------------------------------------- Reporter: Storm Heg | Owner: (none) Type: New feature | Status: new Component: Database layer | Version: (models, ORM) | Severity: Normal | Resolution: Keywords: | Triage Stage: Accepted Has patch: 0 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 -------------------------------------+------------------------------------- Comment (by Simon Charette):
As a clarification the ORM already supports "atomic upsert" through `bulk_create` (as defined by `INSERT ON CONFLICT DO UPDATE`) but lacks a way to set the update value to anything but the value provided by the excluded row on conflict. One thing that we'll need to figure out though is what field references (e.g. `F` or any `str` passed to expressions) should resolve to. Should it be the excluded row (the value specified for associated field of the instance passed to `bulk_create`), should it be the value of conflicting row, or should we allow both by requiring `F('excluded__field')` and `F('conflicting__field')` to be specified? In other words what should the following resolve to {{{#!python PostView.objects.bulk_create( [PostView(post_id=post_id, user_id=user_id, count=0)], unique_fields=["post_id", "user_id"], unique_updates={ "count": F("count") + 1 } ) }}} {{{#!sql INSERT INTO postview(post_id, user_id, count) VALUES(:post_id, :user_id, :count) ON CONFLICT (post_id, user_id) DO UPDATE SET count = postview.update + 1 }}} Stormheg's report requested that it defaults to the conflicting row (not the `excluded` one) and I think it makes the most sense but I'm unsure if all backends support that. Another argument for this using the conflicting row value over the excluded one is that the latter can be emulated with a `Case(When(...))` if necessary (return distinct value based on unique key match) while the other way around is not possible. It's also easier to implement resolving to the `INSERT` table alias (while disallowing JOINs) as no alias re-pointing needs to take place and if a need eventually arise to support excluded references it would be straightforward to implement a `ExcludedF(F)` class that always resolve to the backend specific equivalent of Postgres's `excluded`. -- Ticket URL: <https://code.djangoproject.com/ticket/35793#comment:4> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/django-updates/01070192ba849d6f-f53525e1-b678-4917-86b9-c5ada7299c7d-000000%40eu-central-1.amazonses.com.