Skip to content

Commit

Permalink
Fixed #35384 -- raised FieldError when trying to save ContentFile ins…
Browse files Browse the repository at this point in the history
…tance to File field
  • Loading branch information
jonnythebard committed Apr 28, 2024
1 parent 8c257ce commit f5ff4a8
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 4 deletions.
4 changes: 3 additions & 1 deletion django/core/files/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
from io import BytesIO, StringIO, UnsupportedOperation

from django.core.files.utils import FileProxyMixin
from django.core.files.utils import EmptyName, FileProxyMixin
from django.utils.functional import cached_property


Expand Down Expand Up @@ -124,6 +124,8 @@ class ContentFile(File):
"""

def __init__(self, content, name=None):
if name is None:
name = EmptyName()
stream_class = StringIO if isinstance(content, str) else BytesIO
super().__init__(stream_class(content), name=name)
self.size = len(content)
Expand Down
4 changes: 4 additions & 0 deletions django/core/files/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
from django.core.exceptions import SuspiciousFileOperation


class EmptyName:
pass


def validate_file_name(name, allow_relative_path=False):
# Remove potentially dangerous names
if os.path.basename(name) in {"", ".", ".."}:
Expand Down
5 changes: 4 additions & 1 deletion django/db/models/fields/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@

from django import forms
from django.core import checks
from django.core.exceptions import FieldError
from django.core.files.base import 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
from django.core.files.utils import EmptyName, validate_file_name
from django.db.models import signals
from django.db.models.fields import Field
from django.db.models.query_utils import DeferredAttribute
Expand Down Expand Up @@ -312,6 +313,8 @@ def get_prep_value(self, value):

def pre_save(self, model_instance, add):
file = super().pre_save(model_instance, add)
if isinstance(file.name, EmptyName):
raise FieldError("File name cannot be empty.")
if file and not file._committed:
# Commit the file to storage prior to saving the model
file.save(file.name, file.file, save=False)
Expand Down
3 changes: 2 additions & 1 deletion tests/files/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
TemporaryUploadedFile,
UploadedFile,
)
from django.core.files.utils import EmptyName
from django.test import override_settings

try:
Expand Down Expand Up @@ -236,7 +237,7 @@ def test_noname_file_get_size(self):

class ContentFileTestCase(unittest.TestCase):
def test_content_file_default_name(self):
self.assertIsNone(ContentFile(b"content").name)
self.assertTrue(isinstance(ContentFile(b"content").name, EmptyName))

def test_content_file_custom_name(self):
"""
Expand Down
9 changes: 8 additions & 1 deletion tests/model_fields/test_filefield.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
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
Expand Down Expand Up @@ -72,6 +72,13 @@ def test_save_without_name(self):
with self.assertRaisesMessage(SuspiciousFileOperation, msg):
document.save()

def test_save_content_file_without_name(self):
d = Document()
d.myfile = ContentFile(b"")
msg = "File name cannot be empty."
with self.assertRaisesMessage(FieldError, msg):
d.save()

def test_defer(self):
Document.objects.create(myfile="something.txt")
self.assertEqual(Document.objects.defer("myfile")[0].myfile, "something.txt")
Expand Down

0 comments on commit f5ff4a8

Please sign in to comment.