artofhuman/django-pg-upsert
artofhuman/django-pg-upsert has 31 GitHub stars and 6 forks. GitHot measured 0 stars in 24 hours, 0 in 7 days, and 0 in 15 days. Last checked 2026-11-14 08:59 UTC. Last push 2026-08-12.
Crecimiento de estrellas medido
- in 24h
- 0
- in 7 days
- 0
- in 15 days
- 0
- in 1 month
- Recopilando historial
Cambios netos en períodos que se solapan, no totales diarios. Los datos no disponibles se dejan en blanco. Las estrellas indican interés, no calidad.
Acerca de
Support Postgres native upsert (INSERT ... ON CONFLICT) for django
DatosREADME.md
Originaldjango-pg-upsert
This package adds support for the native Postgres upsert (INSERT ... ON CONFLICT) to Django.
Installation
pip install django-pg-upsert
Usage
As a manager
from django.db import models
from django_pg_upsert import PgUpsertManager
class Pet(models.Model):
name = models.CharField(max_length=30, unique=True)
age = models.PositiveIntegerField()
objects = PgUpsertManager()
Pet.objects.insert_conflict(data={"name": "dog", "age": 12})
# The second query does not insert a record and does not raise an error.
Pet.objects.insert_conflict(data={"name": "dog", "age": 20})
This code produces the SQL statement:
[
'INSERT INTO "pets" ("name", "age") VALUES (%s, %s) ON CONFLICT DO NOTHING',
("dog", 12),
]
Explicit constraint name
Pet.objects.insert_conflict(
data={"name": "dog", "age": 12},
constraint="pet_name_uniq"
)
[
'INSERT INTO "pets" ("name", "age") VALUES (%s, %s) ON CONFLICT ON CONSTRAINT pet_name_uniq DO NOTHING',
("dog", 12),
]
Using field names
Pet.objects.insert_conflict(
data={"name": "dog", "age": 12},
fields=["name"]
)
[
'INSERT INTO "pets" ("name", "age") VALUES (%s, %s) ON CONFLICT ("name") DO NOTHING',
("dog", 12),
]
As a standalone function
import django_pg_upsert
pet = Pet(name="dog", age=12)
django_pg_upsert.insert_conflict(pet)
django_pg_upsert.insert_conflict(pet, constraint="pet_name_uniq")
django_pg_upsert.insert_conflict(pet, fields=["name"])
Update
Pet.objects.insert_conflict(
data={"name": "dog", "age": 100},
fields=["name"],
update=["age"]
)
or
django_pg_upsert.insert_conflict(pet, fields=["name"], update=["age"])
[
'INSERT INTO "pets" ("name", "age") VALUES (%s, %s) ON CONFLICT ("name") DO UPDATE SET age = EXCLUDED.age',
("dog", 100),
]
Update with condition
The update_where argument restricts which existing rows are updated
(ON CONFLICT ... DO UPDATE SET ... WHERE ...). It accepts a Q object.
from django.db.models import Q
Pet.objects.insert_conflict(
data={"name": "dog", "age": 100},
fields=["name"],
update=["age"],
update_where=Q(age__lt=100),
)
[
'INSERT INTO "pets" ("name", "age") VALUES (%s, %s) ON CONFLICT ("name") DO UPDATE SET age = EXCLUDED.age WHERE "pets"."age" < %s',
("dog", 100, 100),
]
The argument also accepts a raw SQL string. Use a raw string to reference the
proposed row through EXCLUDED.
django_pg_upsert.insert_conflict(
pet,
fields=["name"],
update=["age"],
update_where="EXCLUDED.age > pets.age",
)
[
'INSERT INTO "pets" ("name", "age") VALUES (%s, %s) ON CONFLICT ("name") DO UPDATE SET age = EXCLUDED.age WHERE EXCLUDED.age > pets.age',
("dog", 100),
]
Do not build a raw string from user input. The package inlines the string into the statement as is.
Batch
To insert many rows in one statement, pass a list. The manager accepts a list of dictionaries. The standalone function accepts a list of model objects. All other arguments work as they do for a single row.
Pet.objects.insert_conflict(
data=[
{"name": "dog", "age": 12},
{"name": "cat", "age": 8},
],
fields=["name"],
update=["age"],
)
or
dog = Pet(name="dog", age=12)
cat = Pet(name="cat", age=8)
django_pg_upsert.insert_conflict([dog, cat], fields=["name"], update=["age"])
Both calls produce one statement with one row set for each object:
[
'INSERT INTO "pets" ("name", "age") VALUES (%s, %s), (%s, %s) ON CONFLICT ("name") DO UPDATE SET age = EXCLUDED.age',
("dog", 12, "cat", 8),
]
Motivation
django-postgres-extra also has a pg upsert method, but that package requires a different DB backend in the Django settings. Sometimes this change is not possible.
django-pg-upsert solves only one problem and depends only on Django. It is not a Swiss army knife.