From 8deb6bb1fc427762d56646bf7306cbd11fb5bb68 Mon Sep 17 00:00:00 2001 From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Date: Mon, 5 Aug 2024 21:36:49 +0200 Subject: [PATCH] Fixed #35657 -- Made FileField handle db_default values. --- django/db/models/fields/files.py | 7 +++++++ docs/releases/5.0.8.txt | 3 +++ tests/file_storage/models.py | 3 +++ tests/file_storage/tests.py | 14 ++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py index 7c911f4b23..0716d3599e 100644 --- a/django/db/models/fields/files.py +++ b/django/db/models/fields/files.py @@ -9,6 +9,7 @@ from django.core.files.images import ImageFile from django.core.files.storage import Storage, default_storage from django.core.files.utils import validate_file_name from django.db.models import signals +from django.db.models.expressions import DatabaseDefault from django.db.models.fields import Field from django.db.models.query_utils import DeferredAttribute from django.db.models.utils import AltersData @@ -197,6 +198,12 @@ class FileDescriptor(DeferredAttribute): attr = self.field.attr_class(instance, self.field, file) instance.__dict__[self.field.attname] = attr + # If this value is a DatabaseDefault, initialize the attribute class + # for this field with its db_default value. + elif isinstance(file, DatabaseDefault): + attr = self.field.attr_class(instance, self.field, self.field.db_default) + instance.__dict__[self.field.attname] = attr + # Other types of files may be assigned as well, but they need to have # the FieldFile interface added to them. Thus, we wrap any other type of # File inside a FieldFile (well, the field's attr_class, which is diff --git a/docs/releases/5.0.8.txt b/docs/releases/5.0.8.txt index 5cc3faec98..704ecf2c61 100644 --- a/docs/releases/5.0.8.txt +++ b/docs/releases/5.0.8.txt @@ -32,3 +32,6 @@ Bugfixes * Fixed a bug in Django 5.0 which caused constraint validation to either crash or incorrectly raise validation errors for constraints referring to fields using ``Field.db_default`` (:ticket:`35638`). + +* Fixed a crash in Django 5.0 when saving a model containing a ``FileField`` + with a ``db_default`` set (:ticket:`35657`). diff --git a/tests/file_storage/models.py b/tests/file_storage/models.py index 873c3e176a..cb0207cae9 100644 --- a/tests/file_storage/models.py +++ b/tests/file_storage/models.py @@ -72,6 +72,9 @@ class Storage(models.Model): default = models.FileField( storage=temp_storage, upload_to="tests", default="tests/default.txt" ) + db_default = models.FileField( + storage=temp_storage, upload_to="tests", db_default="tests/db_default.txt" + ) empty = models.FileField(storage=temp_storage) limited_length = models.FileField( storage=temp_storage, upload_to="tests", max_length=20 diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py index 868b18dd2c..c7ca873521 100644 --- a/tests/file_storage/tests.py +++ b/tests/file_storage/tests.py @@ -944,6 +944,20 @@ class FileFieldStorageTests(TestCase): self.assertEqual(obj.default.read(), b"default content") obj.default.close() + def test_filefield_db_default(self): + temp_storage.save("tests/db_default.txt", ContentFile("default content")) + obj = Storage.objects.create() + self.assertEqual(obj.db_default.name, "tests/db_default.txt") + self.assertEqual(obj.db_default.read(), b"default content") + obj.db_default.close() + + # File is not deleted, even if there are no more objects using it. + obj.delete() + s = Storage() + self.assertEqual(s.db_default.name, "tests/db_default.txt") + self.assertEqual(s.db_default.read(), b"default content") + s.db_default.close() + def test_empty_upload_to(self): # upload_to can be empty, meaning it does not use subdirectory. obj = Storage()