Skip to content

Commit f4ce6ad

Browse files
authored
Merge pull request #57 from PeterJCLaw/fix-non-id-primary-keys
Have `PostgresQuerySet.insert` always return the primary key
2 parents 8ac712b + 4cbc8a8 commit f4ce6ad

File tree

3 files changed

+149
-4
lines changed

3 files changed

+149
-4
lines changed

psqlextra/manager/manager.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,12 @@ def insert(self, **fields):
187187
if self.conflict_target or self.conflict_action:
188188
compiler = self._build_insert_compiler([fields])
189189
rows = compiler.execute_sql(return_id=True)
190-
if 'id' in rows[0]:
191-
return rows[0]['id']
192-
return None
190+
191+
pk_field_name = self.model._meta.pk.name
192+
return rows[0][pk_field_name]
193193

194194
# no special action required, use the standard Django create(..)
195-
return super().create(**fields).id
195+
return super().create(**fields).pk
196196

197197
def insert_and_get(self, **fields):
198198
"""Creates a new record in the database and then gets

tests/test_insert.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
from django.db import models
2+
3+
from psqlextra.query import ConflictAction
4+
from .util import get_fake_model
5+
6+
7+
def test_insert():
8+
"""Tests whether inserts works when the primary key is explicitly specified."""
9+
10+
model = get_fake_model({
11+
'cookies': models.CharField(max_length=255, null=True),
12+
})
13+
14+
pk = (
15+
model.objects.all()
16+
.insert(
17+
cookies='some-cookies',
18+
)
19+
)
20+
21+
assert pk is not None
22+
23+
obj1 = model.objects.get()
24+
assert obj1.pk == pk
25+
assert obj1.cookies == 'some-cookies'
26+
27+
28+
def test_insert_explicit_pk():
29+
"""Tests whether inserts works when the primary key is explicitly specified."""
30+
31+
model = get_fake_model({
32+
'name': models.CharField(max_length=255, primary_key=True),
33+
'cookies': models.CharField(max_length=255, null=True),
34+
})
35+
36+
pk = (
37+
model.objects.all()
38+
.insert(
39+
name='the-object',
40+
cookies='some-cookies',
41+
)
42+
)
43+
44+
assert pk == 'the-object'
45+
46+
obj1 = model.objects.get()
47+
assert obj1.pk == 'the-object'
48+
assert obj1.name == 'the-object'
49+
assert obj1.cookies == 'some-cookies'
50+
51+
52+
def test_insert_on_conflict():
53+
"""Tests whether inserts works when a conflict is anticipated."""
54+
55+
model = get_fake_model({
56+
'name': models.CharField(max_length=255, unique=True),
57+
'cookies': models.CharField(max_length=255, null=True),
58+
})
59+
60+
pk = (
61+
model.objects.on_conflict([('pk')], ConflictAction.NOTHING)
62+
.insert(
63+
name='the-object',
64+
cookies='some-cookies',
65+
)
66+
)
67+
68+
assert pk is not None
69+
70+
obj1 = model.objects.get()
71+
assert obj1.pk == pk
72+
assert obj1.name == 'the-object'
73+
assert obj1.cookies == 'some-cookies'
74+
75+
76+
def test_insert_on_conflict_explicit_pk():
77+
"""
78+
Tests whether inserts works when a conflict is anticipated and the primary
79+
key is explicitly specified.
80+
"""
81+
82+
model = get_fake_model({
83+
'name': models.CharField(max_length=255, primary_key=True),
84+
'cookies': models.CharField(max_length=255, null=True),
85+
})
86+
87+
pk = (
88+
model.objects.on_conflict([('name')], ConflictAction.NOTHING)
89+
.insert(
90+
name='the-object',
91+
cookies='some-cookies',
92+
)
93+
)
94+
95+
assert pk == 'the-object'
96+
97+
obj1 = model.objects.get()
98+
assert obj1.pk == 'the-object'
99+
assert obj1.name == 'the-object'
100+
assert obj1.cookies == 'some-cookies'

tests/test_upsert.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,51 @@ def test_upsert():
5050
assert obj2.cookies == 'choco'
5151

5252

53+
def test_upsert_explicit_pk():
54+
"""Tests whether upserts works when the primary key is explicitly specified."""
55+
56+
model = get_fake_model({
57+
'name': models.CharField(max_length=255, primary_key=True),
58+
'cookies': models.CharField(max_length=255, null=True),
59+
})
60+
61+
obj1 = (
62+
model.objects
63+
.upsert_and_get(
64+
conflict_target=[('name')],
65+
fields=dict(
66+
name='the-object',
67+
cookies='first-cheers',
68+
)
69+
)
70+
)
71+
72+
obj1.refresh_from_db()
73+
assert obj1.name == 'the-object'
74+
assert obj1.cookies == 'first-cheers'
75+
76+
obj2 = (
77+
model.objects
78+
.upsert_and_get(
79+
conflict_target=[('name')],
80+
fields=dict(
81+
name='the-object',
82+
cookies='second-boo',
83+
)
84+
)
85+
)
86+
87+
obj1.refresh_from_db()
88+
obj2.refresh_from_db()
89+
90+
# assert both objects are the same
91+
assert obj1.pk == obj2.pk
92+
assert obj1.name == 'the-object'
93+
assert obj1.cookies == 'second-boo'
94+
assert obj2.name == 'the-object'
95+
assert obj2.cookies == 'second-boo'
96+
97+
5398
def test_upsert_bulk():
5499
"""Tests whether bulk_upsert works properly."""
55100

0 commit comments

Comments
 (0)