#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 [email protected].
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.