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.
This commit is contained in:
Claude Paroz 2012-06-26 11:14:23 +02:00
parent b6c356b7bb
commit 05d333ba3b
4 changed files with 24 additions and 19 deletions

View File

@ -242,7 +242,11 @@ class FileField(Field):
# (ie. upload_to='path/to/upload/dir'), the length of the generated # (ie. upload_to='path/to/upload/dir'), the length of the generated
# name equals the length of the uploaded name plus a constant. Thus # 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). # 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: if self.max_length and length > self.max_length:
error_values = {'extra': length - self.max_length} error_values = {'extra': length - self.max_length}
raise ValidationError(self.error_messages['max_length'] % error_values) raise ValidationError(self.error_messages['max_length'] % error_values)

View File

@ -26,5 +26,5 @@ class Storage(models.Model):
normal = models.FileField(storage=temp_storage, upload_to='tests') normal = models.FileField(storage=temp_storage, upload_to='tests')
custom = models.FileField(storage=temp_storage, upload_to=custom_upload_to) 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') default = models.FileField(storage=temp_storage, upload_to='tests', default='tests/default.txt')

View File

@ -5,6 +5,7 @@ import shutil
import tempfile import tempfile
from django.core.cache import cache from django.core.cache import cache
from django.core.exceptions import ValidationError
from django.core.files import File from django.core.files import File
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
@ -102,11 +103,23 @@ class FileStorageTests(TestCase):
obj4.random.save("random_file", ContentFile(b"random content")) obj4.random.save("random_file", ContentFile(b"random content"))
self.assertTrue(obj4.random.name.endswith("/random_file")) self.assertTrue(obj4.random.name.endswith("/random_file"))
# Clean up the temporary files and dir. def test_max_length(self):
obj1.normal.delete() """
obj2.normal.delete() Test that FileField validates the length of the generated file name
obj3.default.delete() that will be stored in the database. Regression for #9893.
obj4.random.delete() """
# 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): class FileTests(unittest.TestCase):

View File

@ -365,15 +365,3 @@ class FileFieldTests(unittest.TestCase):
field = d._meta.get_field('myfile') field = d._meta.get_field('myfile')
field.save_form_data(d, 'else.txt') field.save_form_data(d, 'else.txt')
self.assertEqual(d.myfile, '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()