Bulk upsert (INSERT ... ON CONFLICT DO UPDATE)

Django ORM PostgreSQL May 22, 2026 python

bulk_create(update_conflicts=True, unique_fields=[...], update_fields=[...]) compiles to INSERT ...

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# ======================================================================
# `bulk_create(update_conflicts=True, unique_fields=[...], update_fields=[...])`
# compiles to `INSERT ... ON CONFLICT DO UPDATE`: insert the rows, but when a
# row with the same unique key already exists, update just the listed fields
# instead of erroring.
# ======================================================================

# ----------------------------------------------------------------------
# The Hobbit price
# ----------------------------------------------------------------------

# Django:
Book.objects.bulk_create(
    [Book(id=hobbit.id, title="The Hobbit", author=hobbit.author,
          price="99.99", pages=hobbit.pages, published=hobbit.published)],
    update_conflicts=True,
    unique_fields=["id"],
    update_fields=["price"],
)

# SQL:
#   SELECT "examples_author"."id", "examples_author"."name", "examples_author"."bio", "examples_author"."born", "examples_author"."rating", "examples_author"."nickname"
#   FROM "examples_author"
#   WHERE "examples_author"."id" = 47
#   LIMIT 21
#
#   BEGIN
#
#   INSERT INTO "examples_book" ("id", "title", "author_id", "price", "pages", "published", "is_active", "tags", "data", "search")
#   VALUES (62, 'The Hobbit', 47, 99.99, 310, '1937-09-21 00:00:00+00:00'::timestamptz, true, '{}'::varchar(30)[], '{}'::jsonb, NULL)
#   ON CONFLICT("id")
#   DO UPDATE SET "price" = EXCLUDED."price"
#   RETURNING "examples_book"."id", "examples_book"."title_upper"
#
#   COMMIT

# Result:
#   before: $14.50
#   after upsert: $99.99
#   (restored)