Fixed #35657 -- Made FileField handle db_default values.

This commit is contained in:
Sarah Boyce 2024-08-05 21:36:49 +02:00 committed by GitHub
parent e9e14709ff
commit 8deb6bb1fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 27 additions and 0 deletions

View File

@ -9,6 +9,7 @@ from django.core.files.images import ImageFile
from django.core.files.storage import Storage, default_storage from django.core.files.storage import Storage, default_storage
from django.core.files.utils import validate_file_name from django.core.files.utils import validate_file_name
from django.db.models import signals from django.db.models import signals
from django.db.models.expressions import DatabaseDefault
from django.db.models.fields import Field from django.db.models.fields import Field
from django.db.models.query_utils import DeferredAttribute from django.db.models.query_utils import DeferredAttribute
from django.db.models.utils import AltersData from django.db.models.utils import AltersData
@ -197,6 +198,12 @@ class FileDescriptor(DeferredAttribute):
attr = self.field.attr_class(instance, self.field, file) attr = self.field.attr_class(instance, self.field, file)
instance.__dict__[self.field.attname] = attr 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 # 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 # 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 # File inside a FieldFile (well, the field's attr_class, which is

View File

@ -32,3 +32,6 @@ Bugfixes
* Fixed a bug in Django 5.0 which caused constraint validation to either crash * Fixed a bug in Django 5.0 which caused constraint validation to either crash
or incorrectly raise validation errors for constraints referring to fields or incorrectly raise validation errors for constraints referring to fields
using ``Field.db_default`` (:ticket:`35638`). 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`).

View File

@ -72,6 +72,9 @@ class Storage(models.Model):
default = models.FileField( default = models.FileField(
storage=temp_storage, upload_to="tests", default="tests/default.txt" 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) empty = models.FileField(storage=temp_storage)
limited_length = models.FileField( limited_length = models.FileField(
storage=temp_storage, upload_to="tests", max_length=20 storage=temp_storage, upload_to="tests", max_length=20

View File

@ -944,6 +944,20 @@ class FileFieldStorageTests(TestCase):
self.assertEqual(obj.default.read(), b"default content") self.assertEqual(obj.default.read(), b"default content")
obj.default.close() 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): def test_empty_upload_to(self):
# upload_to can be empty, meaning it does not use subdirectory. # upload_to can be empty, meaning it does not use subdirectory.
obj = Storage() obj = Storage()