Skip to content

Commit 4fcc288

Browse files
charettestimgraham
authored andcommitted
Refs #27222 -- Restored Model.save()'s refreshing of db_returning fields even if a value is set.
The logic could likely be adjusted to assign the pre_save value in most cases to avoid the database transit but it could break in subtle ways so it's not worth the complexity it would require. Regression in 9468043. Co-authored-by: Tim Graham <timograham@gmail.com>
1 parent 1e77288 commit 4fcc288

3 files changed

Lines changed: 24 additions & 4 deletions

File tree

django/db/models/base.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,23 +1142,30 @@ def _save_table(
11421142
),
11431143
)["_order__max"]
11441144
)
1145-
fields = [
1145+
insert_fields = [
11461146
f
11471147
for f in meta.local_concrete_fields
11481148
if not f.generated and (pk_set or f is not meta.auto_field)
11491149
]
11501150
returning_fields = list(meta.db_returning_fields)
1151-
for field in fields:
1151+
can_return_columns_from_insert = connections[
1152+
using
1153+
].features.can_return_columns_from_insert
1154+
for field in insert_fields:
11521155
value = (
11531156
getattr(self, field.attname) if raw else field.pre_save(self, False)
11541157
)
11551158
if hasattr(value, "resolve_expression"):
11561159
if field not in returning_fields:
11571160
returning_fields.append(field)
1158-
elif field.db_returning:
1161+
elif (
1162+
field.db_returning
1163+
and not can_return_columns_from_insert
1164+
and not (pk_set and field is meta.auto_field)
1165+
):
11591166
returning_fields.remove(field)
11601167
results = self._do_insert(
1161-
cls._base_manager, using, fields, returning_fields, raw
1168+
cls._base_manager, using, insert_fields, returning_fields, raw
11621169
)
11631170
if results:
11641171
self._assign_returned_values(results[0], returning_fields)

tests/basic/tests.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,14 @@ def test_save_primary_with_falsey_db_default(self):
215215
with self.assertNumQueries(1):
216216
PrimaryKeyWithFalseyDbDefault().save()
217217

218+
def test_auto_field_with_value_refreshed(self):
219+
"""
220+
An auto field must be refreshed by Model.save() even when a value is
221+
set because the database may return a value of a different type.
222+
"""
223+
a = Article.objects.create(pk="123456", pub_date=datetime(2025, 9, 16))
224+
self.assertEqual(a.pk, 123456)
225+
218226

219227
class ModelTest(TestCase):
220228
def test_objects_attribute_is_only_available_on_the_class_itself(self):

tests/queries/test_db_returning.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ def test_insert_returning_non_integer(self):
2626
self.assertTrue(obj.created)
2727
self.assertIsInstance(obj.created, datetime.datetime)
2828

29+
def test_insert_returning_non_integer_from_literal_value(self):
30+
obj = NonIntegerPKReturningModel.objects.create(pk="2025-01-01")
31+
self.assertTrue(obj.created)
32+
self.assertIsInstance(obj.created, datetime.datetime)
33+
2934
def test_insert_returning_multiple(self):
3035
with CaptureQueriesContext(connection) as captured_queries:
3136
obj = ReturningModel.objects.create()

0 commit comments

Comments
 (0)