Commit 3cb87ec6 authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

[1.5.x] Fixed #19525 -- Reverted dcd43831 and 05d333ba.

Refs #9893, #18515.

Thanks Russell for the report.

Backport of db278c3b from master.
parent fbc06eef
Loading
Loading
Loading
Loading
+0 −24
Original line number Diff line number Diff line
@@ -3,7 +3,6 @@ import os

from django import forms
from django.db.models.fields import Field
from django.core.exceptions import ValidationError
from django.core.files.base import File
from django.core.files.storage import default_storage
from django.core.files.images import ImageFile
@@ -207,10 +206,6 @@ class FileDescriptor(object):

class FileField(Field):

    default_error_messages = {
        'max_length': _('Filename is %(extra)d characters too long.')
    }

    # The class to wrap instance attributes in. Accessing the file object off
    # the instance will always return an instance of attr_class.
    attr_class = FieldFile
@@ -233,25 +228,6 @@ class FileField(Field):
        kwargs['max_length'] = kwargs.get('max_length', 100)
        super(FileField, self).__init__(verbose_name, name, **kwargs)

    def validate(self, value, model_instance):
        """
        Validates that the generated file name still fits within max_length.
        """
        # The generated file name stored in the database is generally longer
        # than the uploaded file name. Using the length of generated name in
        # the error message would be confusing. However, in the common case
        # (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).
        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)

    def get_internal_type(self):
        return "FileField"

+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, max_length=16)
    random = models.FileField(storage=temp_storage, upload_to=random_upload_to)
    default = models.FileField(storage=temp_storage, upload_to='tests', default='tests/default.txt')
+0 −19
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@ 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
@@ -103,24 +102,6 @@ class FileStorageTests(TestCase):
        obj4.random.save("random_file", ContentFile("random content"))
        self.assertTrue(obj4.random.name.endswith("/random_file"))

    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):
    def test_context_manager(self):