Index: django/db/models/fields/__init__.py
===================================================================
--- django/db/models/fields/__init__.py (revision 4664)
+++ django/db/models/fields/__init__.py (working copy)
@@ -662,6 +662,11 @@
else:
func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"], save)
+ def formfield_save_file(self, field_name, new_data, new_object, save=True):
+ if new_data[field_name][0]:
+ func = getattr(new_object, 'save_%s_file' % self.name)
+ func(new_data[field_name][0]["filename"], new_data[field_name][0]["content"], save)
+
def get_directory_name(self):
return os.path.normpath(datetime.datetime.now().strftime(self.upload_to))
@@ -670,6 +675,11 @@
f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
return os.path.normpath(f)
+ def formfield(self, **kwargs):
+ defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'widget': forms.FileInput}
+ defaults.update(kwargs)
+ return forms.FileField(**defaults)
+
class FilePathField(Field):
def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
self.path, self.match, self.recursive = path, match, recursive
@@ -716,6 +726,11 @@
setattr(new_object, self.height_field, getattr(original_object, self.height_field))
new_object.save()
+ def formfield(self, **kwargs):
+ defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'widget': forms.FileInput}
+ defaults.update(kwargs)
+ return forms.ImageField(**defaults)
+
class IntegerField(Field):
empty_strings_allowed = False
def get_manipulator_field_objs(self):
Index: django/newforms/models.py
===================================================================
--- django/newforms/models.py (revision 4664)
+++ django/newforms/models.py (working copy)
@@ -18,6 +18,7 @@
This method is created for any form_for_model Form.
"""
+ from django.db import models
if self.errors:
raise ValueError("The %s could not be created because the data didn't validate." % self._model._meta.object_name)
return save_instance(self, self._model(), commit)
@@ -38,6 +39,9 @@
for f in opts.fields:
if not f.editable or isinstance(f, models.AutoField):
continue
+ if isinstance(f,models.FileField):
+ f.formfield_save_file(f.name, clean_data, instance, save=False)
+ continue
setattr(instance, f.name, clean_data[f.name])
if commit:
instance.save()
Index: django/newforms/fields.py
===================================================================
--- django/newforms/fields.py (revision 4664)
+++ django/newforms/fields.py (working copy)
@@ -10,7 +10,7 @@
import time
__all__ = (
- 'Field', 'CharField', 'IntegerField',
+ 'Field', 'CharField', 'FileField', 'ImageField', 'IntegerField',
'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
'DEFAULT_TIME_INPUT_FORMATS', 'TimeField',
'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
@@ -107,6 +107,44 @@
if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
return {'maxlength': str(self.max_length)}
+class FileField(Field):
+
+ prev_error = False
+
+ def clean(self, value):
+ super(FileField, self).clean(value)
+
+ if value[0]:
+ try:
+ content = value[0]['content']
+ except TypeError:
+ self.prev_error = True
+ raise ValidationError(gettext("No file was submitted. Check the encoding type on the form."))
+
+ if not content:
+ self.prev_error = True
+ raise ValidationError(gettext(u'The submitted file is empty.'))
+
+ elif self.required:
+ if not value[1]:
+ self.prev_error = True
+ raise ValidationError(gettext(u'This field is required.'))
+
+ return value
+
+class ImageField(FileField):
+
+ def clean(self, value):
+ super(ImageField, self).clean(value)
+ if value[0] and not self.prev_error:
+ from PIL import Image
+ from cStringIO import StringIO
+ try:
+ Image.open(StringIO(value[0]['content']))
+ except IOError: # Python Imaging Library doesn't recognize it as an image
+ raise ValidationError, gettext(u'Upload a valid image. The file you uploaded was either not an image or a corrupted image.')
+ return value
+
class IntegerField(Field):
def __init__(self, max_value=None, min_value=None, *args, **kwargs):
self.max_value, self.min_value = max_value, min_value
Index: django/newforms/widgets.py
===================================================================
--- django/newforms/widgets.py (revision 4664)
+++ django/newforms/widgets.py (working copy)
@@ -115,6 +115,24 @@
class FileInput(Input):
input_type = 'file'
+
+ def render(self,name,value,attrs=None,choices=()):
+ if value is None: value = ''
+ file_attrs = self.build_attrs(attrs, type='file', name=name+'_file')
+ final_attrs = self.build_attrs(attrs, type='hidden', name=name)
+ if value != '': final_attrs['value'] = smart_unicode(value) # only add the value attribute if a value is non-empty
+
+ if value != '':
+ currently = u'Currently: %s
Change: ' % smart_unicode(value)
+ current = u' ' % flatatt(final_attrs)
+ else:
+ currently = u''
+ current = u''
+
+ return u'%s%s' % (currently,flatatt(file_attrs),current)
+
+ def value_from_datadict(self,data,name):
+ return [data.get(name+'_file',None),data.get(name,None)]
class Textarea(Widget):
def render(self, name, value, attrs=None):
Index: tests/modeltests/model_forms/models.py
===================================================================
--- tests/modeltests/model_forms/models.py (revision 4664)
+++ tests/modeltests/model_forms/models.py (working copy)
@@ -61,6 +61,20 @@
def __str__(self):
return self.phone
+class NotRequiredFile(models.Model):
+ description = models.CharField(maxlength=50)
+ file = models.FileField(upload_to='files', blank=True)
+
+ def __str__(self):
+ return self.description
+
+class RequiredFile(models.Model):
+ description = models.CharField(maxlength=50)
+ file = models.FileField(upload_to='files')
+
+ def __str__(self):
+ return self.description
+
__test__ = {'API_TESTS': """
>>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField
>>> import datetime
@@ -377,6 +391,52 @@
>>> f = ModelChoiceField(Category.objects.filter(pk=1), required=False)
>>> print f.clean('')
+
+Test for filefield
+
+>>> form_data = {'description': 'FileField test', 'file_file': {'content': 'FileField test', 'filename': 'filetest.txt'} }
+>>> no_file_form_data = {'description': 'FileField test'}
+>>> just_path_form_data = {'description': 'FileField test', 'file': 'files/filetest.txt'}
+>>> bad_encoding_form_data = {'description': 'FileField test', 'file': 'files/filetest.txt', 'file_file': 'wrong encoding'}
+>>> TestRequiredFileForm = form_for_model(RequiredFile)
+>>> empty_required_fileform = TestRequiredFileForm(auto_id=False)
+>>> print empty_required_fileform.as_ul()
+