#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.

Reply via email to