Skip to content

Commit d956b52

Browse files
committed
Cope with foreign keys which are primary keys
This removes the assumption that all models have a field called 'id' and ensures that we use the correct column name for each field. Fixes #40.
1 parent 65c5fff commit d956b52

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
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: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,46 @@ def test_on_conflict_nothing():
3939
assert obj1.cookies == 'cheers'
4040
assert obj2.title['key1'] == 'beer'
4141
assert obj2.cookies == 'cheers'
42+
43+
44+
def test_on_conflict_nothing_foreign_primary_key():
45+
"""
46+
Tests whether simple insert NOTHING works correctly when the primary key of
47+
a field is a foreign key with a custom name.
48+
"""
49+
50+
referenced_model = get_fake_model({})
51+
52+
model = get_fake_model({
53+
'parent': models.OneToOneField(
54+
referenced_model,
55+
primary_key=True,
56+
on_delete=models.CASCADE,
57+
),
58+
'cookies': models.CharField(max_length=255, null=True)
59+
})
60+
61+
referenced_obj = referenced_model.objects.create()
62+
63+
obj1 = (
64+
model.objects
65+
.on_conflict(['parent'], ConflictAction.NOTHING)
66+
.insert_and_get(parent=referenced_obj, cookies='cheers')
67+
)
68+
69+
obj1.refresh_from_db()
70+
assert obj1.parent == referenced_obj
71+
assert obj1.cookies == 'cheers'
72+
73+
obj2 = (
74+
model.objects
75+
.on_conflict(['parent'], ConflictAction.NOTHING)
76+
.insert_and_get(parent=referenced_obj, cookies='choco')
77+
)
78+
79+
obj1.refresh_from_db()
80+
obj2.refresh_from_db()
81+
82+
assert obj1.pk == obj2.pk
83+
assert obj1.cookies == 'cheers'
84+
assert obj2.cookies == 'cheers'

0 commit comments

Comments
 (0)