Skip to content

Commit 487ec1e

Browse files
authored
Merge pull request #41 from PeterJCLaw/fix-foreign-primary-key-on-conflict-do-nothing
Cope with foreign keys which are primary keys
2 parents 0124f08 + 47513db commit 487ec1e

File tree

2 files changed

+46
-2
lines changed

2 files changed

+46
-2
lines changed

psqlextra/compiler.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,13 @@ def _rewrite_insert_nothing(self, sql, params, returning):
155155
(
156156
'WITH insdata AS ('
157157
'{insert} ON CONFLICT {conflict_target} DO UPDATE'
158-
' SET id = NULL WHERE FALSE RETURNING {returning})'
158+
' SET {pk_column} = NULL WHERE FALSE RETURNING {returning})'
159159
' SELECT * FROM insdata UNION ALL'
160160
' SELECT {returning} FROM {table} WHERE {where_clause} LIMIT 1;'
161161
).format(
162162
insert=sql,
163163
conflict_target=conflict_target,
164+
pk_column=self.qn(self.query.model._meta.pk.column),
164165
returning=returning,
165166
table=self.query.objs[0]._meta.db_table,
166167
where_clause=where_clause

tests/test_on_conflict_nothing.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,49 @@ def test_on_conflict_nothing():
4242
assert obj2.cookies == 'cheers'
4343

4444

45+
def test_on_conflict_nothing_foreign_primary_key():
46+
"""
47+
Tests whether simple insert NOTHING works correctly when the primary key of
48+
a field is a foreign key with a custom name.
49+
"""
50+
51+
referenced_model = get_fake_model({})
52+
53+
model = get_fake_model({
54+
'parent': models.OneToOneField(
55+
referenced_model,
56+
primary_key=True,
57+
on_delete=models.CASCADE,
58+
),
59+
'cookies': models.CharField(max_length=255),
60+
})
61+
62+
referenced_obj = referenced_model.objects.create()
63+
64+
obj1 = (
65+
model.objects
66+
.on_conflict(['parent_id'], ConflictAction.NOTHING)
67+
.insert_and_get(parent_id=referenced_obj.pk, cookies='cheers')
68+
)
69+
70+
obj1.refresh_from_db()
71+
assert obj1.parent == referenced_obj
72+
assert obj1.cookies == 'cheers'
73+
74+
obj2 = (
75+
model.objects
76+
.on_conflict(['parent_id'], ConflictAction.NOTHING)
77+
.insert_and_get(parent_id=referenced_obj.pk, cookies='choco')
78+
)
79+
80+
obj1.refresh_from_db()
81+
obj2.refresh_from_db()
82+
83+
assert obj1.pk == obj2.pk
84+
assert obj1.cookies == 'cheers'
85+
assert obj2.cookies == 'cheers'
86+
87+
4588
def test_on_conflict_nothing_foreign_key_by_object():
4689
"""
4790
Tests whether simple insert NOTHING works correctly when the potentially
@@ -148,4 +191,4 @@ def test_on_conflict_nothing_foreign_key_by_id():
148191
assert obj1.other == other_obj
149192
assert obj2.other == other_obj
150193
assert obj1.data == "some data"
151-
assert obj2.data == "some data"
194+
assert obj2.data == "some data"

0 commit comments

Comments
 (0)