Fixed #35384 -- Raised FieldError when saving a file without a name to FileField.

This commit is contained in:
Jonny Park 2024-04-28 11:54:54 +09:00 committed by Sarah Boyce
parent b691accea1
commit c0b0ce85ed
3 changed files with 39 additions and 2 deletions

View File

@ -3,7 +3,8 @@ import posixpath
from django import forms
from django.core import checks
from django.core.files.base import File
from django.core.exceptions import FieldError
from django.core.files.base import ContentFile, File
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
@ -12,6 +13,7 @@ from django.db.models.fields import Field
from django.db.models.query_utils import DeferredAttribute
from django.db.models.utils import AltersData
from django.utils.translation import gettext_lazy as _
from django.utils.version import PY311
class FieldFile(File, AltersData):
@ -312,6 +314,15 @@ class FileField(Field):
def pre_save(self, model_instance, add):
file = super().pre_save(model_instance, add)
if file.name is None and file._file is not None:
exc = FieldError(
f"File for {self.name} must have "
"the name attribute specified to be saved."
)
if PY311 and isinstance(file._file, ContentFile):
exc.add_note("Pass a 'name' argument to ContentFile.")
raise exc
if file and not file._committed:
# Commit the file to storage prior to saving the model
file.save(file.name, file.file, save=False)

View File

@ -425,6 +425,10 @@ Miscellaneous
* The minimum supported version of SQLite is increased from 3.27.0 to 3.31.0.
* :class:`~django.db.models.FileField` now raises a
:class:`~django.core.exceptions.FieldError` when saving a file without a
``name``.
.. _deprecated-features-5.1:
Features deprecated in 5.1

View File

@ -5,13 +5,14 @@ import tempfile
import unittest
from pathlib import Path
from django.core.exceptions import SuspiciousFileOperation
from django.core.exceptions import FieldError, SuspiciousFileOperation
from django.core.files import File, temp
from django.core.files.base import ContentFile
from django.core.files.uploadedfile import TemporaryUploadedFile
from django.db import IntegrityError, models
from django.test import TestCase, override_settings
from django.test.utils import isolate_apps
from django.utils.version import PY311
from .models import Document
@ -72,6 +73,27 @@ class FileFieldTests(TestCase):
with self.assertRaisesMessage(SuspiciousFileOperation, msg):
document.save()
def test_save_content_file_without_name(self):
d = Document()
d.myfile = ContentFile(b"")
msg = "File for myfile must have the name attribute specified to be saved."
with self.assertRaisesMessage(FieldError, msg) as cm:
d.save()
if PY311:
self.assertEqual(
cm.exception.__notes__, ["Pass a 'name' argument to ContentFile."]
)
def test_delete_content_file(self):
file = ContentFile(b"", name="foo")
d = Document.objects.create(myfile=file)
d.myfile.delete()
self.assertIsNone(d.myfile.name)
msg = "The 'myfile' attribute has no file associated with it."
with self.assertRaisesMessage(ValueError, msg):
getattr(d.myfile, "file")
def test_defer(self):
Document.objects.create(myfile="something.txt")
self.assertEqual(Document.objects.defer("myfile")[0].myfile, "something.txt")