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:
parent
82a76ef67d
commit
dcd4383107
|
@ -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"
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue