From fe189dc43ab3eddbbceefb6834893b73ca60d5ed Mon Sep 17 00:00:00 2001 From: Nilesh Kumar Pahari Date: Mon, 26 Jan 2026 00:02:29 +0530 Subject: [PATCH] Fixed #36847 -- Ensured auto_now_add fields are set on pre_save(). Regression in 94680437a45a71c70ca8bd2e68b72aa1e2eff337. Refs #27222. During INSERT operations, `field.pre_save()` is called to prepare values for db insertion. The `add` param must be `True` for `auto_now_add` fields to be populated. The regression commit passed `False`, causing `auto_now_add` fields to remain `None` when used by other fields, such as `upload_to` callables. Thanks Ran Benita for the report. --- django/db/models/base.py | 4 +++- docs/releases/6.0.2.txt | 3 +++ tests/model_fields/models.py | 10 ++++++++++ tests/model_fields/test_filefield.py | 8 +++++++- 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/django/db/models/base.py b/django/db/models/base.py index ad3f0c5e23..d53da600d7 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -1175,7 +1175,9 @@ class Model(AltersData, metaclass=ModelBase): ].features.can_return_columns_from_insert for field in insert_fields: value = ( - getattr(self, field.attname) if raw else field.pre_save(self, False) + getattr(self, field.attname) + if raw + else field.pre_save(self, add=True) ) if hasattr(value, "resolve_expression"): if field not in returning_fields: diff --git a/docs/releases/6.0.2.txt b/docs/releases/6.0.2.txt index b25f1af472..d74a8bd763 100644 --- a/docs/releases/6.0.2.txt +++ b/docs/releases/6.0.2.txt @@ -15,3 +15,6 @@ Bugfixes to wrap below the changelist when filter elements contained long text (:ticket:`36850`). +* Fixed a regression in Django 6.0 where ``auto_now_add`` field values were not + populated during ``INSERT`` operations, due to incorrect parameters passed to + ``field.pre_save()`` (:ticket:`36847`). diff --git a/tests/model_fields/models.py b/tests/model_fields/models.py index 1d8a447dee..a594b89adb 100644 --- a/tests/model_fields/models.py +++ b/tests/model_fields/models.py @@ -262,10 +262,20 @@ class DataModel(models.Model): # FileField +def upload_to_with_date(instance, filename): + return f"{instance.created_at.year}/{filename}" + + class Document(models.Model): myfile = models.FileField(storage=temp_storage, upload_to="unused", unique=True) +# See ticket #36847. +class DocumentWithTimestamp(models.Model): + created_at = models.DateTimeField(auto_now_add=True) + myfile = models.FileField(storage=temp_storage, upload_to=upload_to_with_date) + + ############################################################################### # ImageField diff --git a/tests/model_fields/test_filefield.py b/tests/model_fields/test_filefield.py index 57cc7365da..fbf5c837ac 100644 --- a/tests/model_fields/test_filefield.py +++ b/tests/model_fields/test_filefield.py @@ -13,7 +13,7 @@ from django.db import IntegrityError, models from django.test import TestCase, override_settings from django.test.utils import isolate_apps -from .models import Document +from .models import Document, DocumentWithTimestamp class FileFieldTests(TestCase): @@ -209,3 +209,9 @@ class FileFieldTests(TestCase): document = MyDocument(myfile="test_file.py") self.assertEqual(document.myfile.field.model, MyDocument) + + def test_upload_to_callable_sees_auto_now_add_field_value(self): + d = DocumentWithTimestamp(myfile=ContentFile(b"content", name="foo")) + d.save() + self.assertIsNotNone(d.created_at) + self.assertIs(d.myfile.name.startswith(f"{d.created_at.year}/foo"), True)