From fea6c73538148a7362a9cdd85bbc4732ddb4204d Mon Sep 17 00:00:00 2001
From: Joseph Kocherhans <joseph@jkocherhans.com>
Date: Mon, 30 Mar 2009 22:52:16 +0000
Subject: [PATCH] Fixed #10149. FileFields in a form now validate max_length.
 Based on a patch by Massimo Scamarcia.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@10227 bcc190cf-cafb-0310-a4f2-bffc1f526a37
---
 AUTHORS                                |  1 +
 django/db/models/fields/files.py       |  2 +-
 django/forms/fields.py                 |  5 +++++
 tests/modeltests/model_forms/models.py |  7 ++++++-
 tests/regressiontests/forms/fields.py  | 15 +++++++++++++++
 5 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index f47bdb4175..649b35d373 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -364,6 +364,7 @@ answer newbie questions, and generally made Django that much better:
     Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
     Vinay Sajip <vinay_sajip@yahoo.co.uk>
     Kadesarin Sanjek
+    Massimo Scamarcia <massimo.scamarcia@gmail.com>
     David Schein
     Bernd Schlapsi
     scott@staplefish.com
diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py
index cfc434741b..43853369d1 100644
--- a/django/db/models/fields/files.py
+++ b/django/db/models/fields/files.py
@@ -222,7 +222,7 @@ class FileField(Field):
             setattr(instance, self.name, data)
 
     def formfield(self, **kwargs):
-        defaults = {'form_class': forms.FileField}
+        defaults = {'form_class': forms.FileField, 'max_length': self.max_length}
         # If a file has been provided previously, then the form doesn't require
         # that a new file is provided this time.
         # The code to mark the form field as not required is used by
diff --git a/django/forms/fields.py b/django/forms/fields.py
index a414e76890..9c4084450a 100644
--- a/django/forms/fields.py
+++ b/django/forms/fields.py
@@ -447,9 +447,11 @@ class FileField(Field):
         'invalid': _(u"No file was submitted. Check the encoding type on the form."),
         'missing': _(u"No file was submitted."),
         'empty': _(u"The submitted file is empty."),
+        'max_length': _(u'Ensure this filename has at most %(max)d characters (it has %(length)d).'),
     }
 
     def __init__(self, *args, **kwargs):
+        self.max_length = kwargs.pop('max_length', None)
         super(FileField, self).__init__(*args, **kwargs)
 
     def clean(self, data, initial=None):
@@ -466,6 +468,9 @@ class FileField(Field):
         except AttributeError:
             raise ValidationError(self.error_messages['invalid'])
 
+        if self.max_length is not None and len(file_name) > self.max_length:
+            error_values =  {'max': self.max_length, 'length': len(file_name)}
+            raise ValidationError(self.error_messages['max_length'] % error_values)
         if not file_name:
             raise ValidationError(self.error_messages['invalid'])
         if not file_size:
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
index 4075250482..c540319549 100644
--- a/tests/modeltests/model_forms/models.py
+++ b/tests/modeltests/model_forms/models.py
@@ -93,7 +93,7 @@ class PhoneNumber(models.Model):
 
 class TextFile(models.Model):
     description = models.CharField(max_length=20)
-    file = models.FileField(storage=temp_storage, upload_to='tests')
+    file = models.FileField(storage=temp_storage, upload_to='tests', max_length=15)
 
     def __unicode__(self):
         return self.description
@@ -1018,6 +1018,11 @@ True
 >>> instance.file
 <FieldFile: tests/test1.txt>
 
+# Check if the max_length attribute has been inherited from the model.
+>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test-maxlength.txt', 'hello world')})
+>>> f.is_valid()
+False
+
 # Edit an instance that already has the file defined in the model. This will not
 # save the file again, but leave it exactly as it is.
 
diff --git a/tests/regressiontests/forms/fields.py b/tests/regressiontests/forms/fields.py
index fa5a62ac51..0dc49f2ca7 100644
--- a/tests/regressiontests/forms/fields.py
+++ b/tests/regressiontests/forms/fields.py
@@ -845,6 +845,21 @@ ValidationError: [u'The submitted file is empty.']
 >>> type(f.clean(SimpleUploadedFile('name', 'Some File Content'), 'files/test4.pdf'))
 <class 'django.core.files.uploadedfile.SimpleUploadedFile'>
 
+>>> f = FileField(max_length = 5)
+>>> f.clean(SimpleUploadedFile('test_maxlength.txt', 'hello world'))
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this filename has at most 5 characters (it has 18).']
+
+>>> f.clean('', 'files/test1.pdf')
+'files/test1.pdf'
+
+>>> f.clean(None, 'files/test2.pdf')
+'files/test2.pdf'
+
+>>> type(f.clean(SimpleUploadedFile('name', 'Some File Content')))
+<class 'django.core.files.uploadedfile.SimpleUploadedFile'>
+
 # URLField ##################################################################
 
 >>> f = URLField()