summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2012-05-17 16:02:05 +0200
committerAymeric Augustin <aymeric.augustin@m4x.org>2012-05-17 16:02:05 +0200
commitdcd4383107d96c18bcb53312ca4de070374b334c (patch)
tree674b9d393cc35a63fff255b5b58a8e359f3566d3
parent82a76ef67d944b1a4507cac81476bebba0c90e4a (diff)
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.
-rw-r--r--django/db/models/fields/files.py21
-rw-r--r--tests/regressiontests/model_fields/tests.py12
2 files changed, 33 insertions, 0 deletions
diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py
index 6f1f183d4f..34cf84dbc0 100644
--- a/django/db/models/fields/files.py
+++ b/django/db/models/fields/files.py
@@ -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"
diff --git a/tests/regressiontests/model_fields/tests.py b/tests/regressiontests/model_fields/tests.py
index ea1e1c7d99..4b48616e99 100644
--- a/tests/regressiontests/model_fields/tests.py
+++ b/tests/regressiontests/model_fields/tests.py
@@ -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()