summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2025-09-16 18:10:27 -0400
committerJacob Walls <jacobtylerwalls@gmail.com>2025-09-17 07:50:08 -0400
commit4fcc2883faa8e33152d9e45744354cff35636975 (patch)
tree957e44834efe98133950ebf727e5bef7ef25301a
parent1e7728888dbbff437ad9847c82b84feb81f785df (diff)
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 94680437a45a71c70ca8bd2e68b72aa1e2eff337. Co-authored-by: Tim Graham <timograham@gmail.com>
-rw-r--r--django/db/models/base.py15
-rw-r--r--tests/basic/tests.py8
-rw-r--r--tests/queries/test_db_returning.py5
3 files changed, 24 insertions, 4 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 82ea520065..36b16c1132 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -1142,23 +1142,30 @@ class Model(AltersData, metaclass=ModelBase):
),
)["_order__max"]
)
- fields = [
+ insert_fields = [
f
for f in meta.local_concrete_fields
if not f.generated and (pk_set or f is not meta.auto_field)
]
returning_fields = list(meta.db_returning_fields)
- for field in fields:
+ can_return_columns_from_insert = connections[
+ using
+ ].features.can_return_columns_from_insert
+ for field in insert_fields:
value = (
getattr(self, field.attname) if raw else field.pre_save(self, False)
)
if hasattr(value, "resolve_expression"):
if field not in returning_fields:
returning_fields.append(field)
- elif field.db_returning:
+ elif (
+ field.db_returning
+ and not can_return_columns_from_insert
+ and not (pk_set and field is meta.auto_field)
+ ):
returning_fields.remove(field)
results = self._do_insert(
- cls._base_manager, using, fields, returning_fields, raw
+ cls._base_manager, using, insert_fields, returning_fields, raw
)
if results:
self._assign_returned_values(results[0], returning_fields)
diff --git a/tests/basic/tests.py b/tests/basic/tests.py
index 38e7278210..38d7d2a3d6 100644
--- a/tests/basic/tests.py
+++ b/tests/basic/tests.py
@@ -215,6 +215,14 @@ class ModelInstanceCreationTests(TestCase):
with self.assertNumQueries(1):
PrimaryKeyWithFalseyDbDefault().save()
+ def test_auto_field_with_value_refreshed(self):
+ """
+ An auto field must be refreshed by Model.save() even when a value is
+ set because the database may return a value of a different type.
+ """
+ a = Article.objects.create(pk="123456", pub_date=datetime(2025, 9, 16))
+ self.assertEqual(a.pk, 123456)
+
class ModelTest(TestCase):
def test_objects_attribute_is_only_available_on_the_class_itself(self):
diff --git a/tests/queries/test_db_returning.py b/tests/queries/test_db_returning.py
index 06efe023e1..032a2823cb 100644
--- a/tests/queries/test_db_returning.py
+++ b/tests/queries/test_db_returning.py
@@ -26,6 +26,11 @@ class ReturningValuesTests(TestCase):
self.assertTrue(obj.created)
self.assertIsInstance(obj.created, datetime.datetime)
+ def test_insert_returning_non_integer_from_literal_value(self):
+ obj = NonIntegerPKReturningModel.objects.create(pk="2025-01-01")
+ self.assertTrue(obj.created)
+ self.assertIsInstance(obj.created, datetime.datetime)
+
def test_insert_returning_multiple(self):
with CaptureQueriesContext(connection) as captured_queries:
obj = ReturningModel.objects.create()