Commit 05d333ba authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #18515 -- Conditionally regenerated filename in FileField validation

When a FileField value has been saved, a new validation should not
regenerate a new filename when checking the length. Refs #9893.
parent b6c356b7
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -242,7 +242,11 @@ class FileField(Field):
        # (ie. upload_to='path/to/upload/dir'), the length of the generated
        # name equals the length of the uploaded name plus a constant. Thus
        # we can tell the user how much shorter the name should be (roughly).
        length = len(self.generate_filename(model_instance, value.name))
        if value and value._committed:
            filename = value.name
        else:
            filename = self.generate_filename(model_instance, value.name)
        length = len(filename)
        if self.max_length and length > self.max_length:
            error_values = {'extra': length - self.max_length}
            raise ValidationError(self.error_messages['max_length'] % error_values)
+1 −1
Original line number Diff line number Diff line
@@ -26,5 +26,5 @@ class Storage(models.Model):

    normal = models.FileField(storage=temp_storage, upload_to='tests')
    custom = models.FileField(storage=temp_storage, upload_to=custom_upload_to)
    random = models.FileField(storage=temp_storage, upload_to=random_upload_to)
    random = models.FileField(storage=temp_storage, upload_to=random_upload_to, max_length=16)
    default = models.FileField(storage=temp_storage, upload_to='tests', default='tests/default.txt')
+18 −5
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ import shutil
import tempfile

from django.core.cache import cache
from django.core.exceptions import ValidationError
from django.core.files import File
from django.core.files.base import ContentFile
from django.core.files.uploadedfile import SimpleUploadedFile
@@ -102,11 +103,23 @@ class FileStorageTests(TestCase):
        obj4.random.save("random_file", ContentFile(b"random content"))
        self.assertTrue(obj4.random.name.endswith("/random_file"))

        # Clean up the temporary files and dir.
        obj1.normal.delete()
        obj2.normal.delete()
        obj3.default.delete()
        obj4.random.delete()
    def test_max_length(self):
        """
        Test that FileField validates the length of the generated file name
        that will be stored in the database. Regression for #9893.
        """
        # upload_to = 'unused', so file names are saved as '456/xxxxx'.
        # max_length = 16, so names longer than 12 characters are rejected.
        s1 = Storage(random=SimpleUploadedFile(12 * 'x', b"content"))
        s1.full_clean()
        with self.assertRaises(ValidationError):
            Storage(random=SimpleUploadedFile(13 * 'x', b"content")).full_clean()

        # Ticket #18515: validation for an already saved file should not check
        # against a regenerated file name (and potentially raise a ValidationError
        # if max_length is exceeded
        s1.save()
        s1.full_clean()


class FileTests(unittest.TestCase):
+0 −12
Original line number Diff line number Diff line
@@ -365,15 +365,3 @@ class FileFieldTests(unittest.TestCase):
        field = d._meta.get_field('myfile')
        field.save_form_data(d, 'else.txt')
        self.assertEqual(d.myfile, 'else.txt')

    def test_max_length(self):
        """
        Test that FileField validates the length of the generated file name
        that will be stored in the database. Regression for #9893.

        """
        # upload_to = 'unused', so file names are saved as 'unused/xxxxx'.
        # max_length = 100, so names longer than 93 characters are rejected.
        Document(myfile=93 * 'x').full_clean()
        with self.assertRaises(ValidationError):
            Document(myfile=94 * 'x').full_clean()