Fixed #9893 -- Validated the length of file names

after the full file name is generated by the storage class.

Thanks Refefer for the report, carsongee for the patch, and
everyone else involved in the discussion.
This commit is contained in:
Aymeric Augustin 2012-05-17 16:02:05 +02:00
parent 82a76ef67d
commit dcd4383107
2 changed files with 33 additions and 0 deletions

View File

@ -3,6 +3,7 @@ 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
@ -204,6 +205,11 @@ class FileDescriptor(object):
instance.__dict__[self.field.name] = value
class FileField(Field):
default_error_messages = {
'max_length': _(u'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
@ -226,6 +232,21 @@ 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).
length = len(self.generate_filename(model_instance, value.name))
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"

View File

@ -365,3 +365,15 @@ 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()