Index: django/db/models/fields/__init__.py
===================================================================
--- django/db/models/fields/__init__.py	(revision 4722)
+++ 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]:
+            func = getattr(new_object, 'save_%s_file' % self.name)
+            func(new_data[field_name]["filename"], new_data[field_name]["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 4722)
+++ 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)
@@ -36,9 +37,18 @@
         raise ValueError("The %s could not be changed because the data didn't validate." % opts.object_name)
     clean_data = form.clean_data
     for f in opts.fields:
-        if not f.editable or isinstance(f, models.AutoField):
-            continue
-        setattr(instance, f.name, clean_data[f.name])
+        if clean_data.has_key(f.name):
+            if not f.editable or isinstance(f, models.AutoField):
+                continue
+            if isinstance(f, models.FileField):
+                continue
+            setattr(instance, f.name, clean_data[f.name])
+
+    # FileField may need more info to save to specific paths
+    for f in opts.fields:
+        if isinstance(f, models.FileField) and clean_data.has_key(f.name):
+            f.formfield_save_file(f.name, clean_data, instance, save=False)
+
     if commit:
         instance.save()
         for f in opts.many_to_many:
@@ -87,6 +97,7 @@
     takes a database Field instance, plus **kwargs, and returns a form Field
     instance with the given kwargs (i.e. 'initial').
     """
+    from django.db import models
     model = instance.__class__
     opts = model._meta
     field_list = []
@@ -96,6 +107,10 @@
         current_value = f.value_from_object(instance)
         formfield = formfield_callback(f, initial=current_value)
         if formfield:
+            # FileFields are only required once, because we cannot print the
+            # existing data into the <form>
+            if isinstance(f, models.FileField) and current_value:
+                formfield.has_file_uploaded = False
             field_list.append((f.name, formfield))
     fields = SortedDictFromList(field_list)
     return type(opts.object_name + 'InstanceForm', (form,),
Index: django/newforms/fields.py
===================================================================
--- django/newforms/fields.py	(revision 4722)
+++ 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,39 @@
         if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
             return {'maxlength': str(self.max_length)}
 
+class FileField(Field):
+    prev_error = False
+    has_file_uploaded = False
+    
+    def clean(self, value):
+        super(FileField, self).clean(value)
+        if value:
+            try:
+                content = value['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 and not self.has_file_uploaded:
+            if not value:
+                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 and not self.prev_error:
+            from PIL import Image
+            from cStringIO import StringIO
+            try:
+                Image.open(StringIO(value['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: tests/modeltests/model_forms/models.py
===================================================================
--- tests/modeltests/model_forms/models.py	(revision 4722)
+++ 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()
+<li>Description: <input type="text" name="description" maxlength="50" /></li>
+<li>File: <input type="file" name="file_file" /></li>
+
+Test with data
+>>> filled_required_fileform= TestRequiredFileForm(form_data, auto_id=False)
+>>> filled_required_fileform.is_valid()
+True
+
+>>> required_file_instance = filled_required_fileform.save()
+>>> print required_file_instance.file
+files/filetest.txt
+>>> TestInstanceRequiredFileForm = form_for_instance(required_file_instance)
+>>> instance_required_fileform = TestInstanceRequiredFileForm(auto_id=False)
+>>> instance_required_fileform.as_ul()
+u'<li>Description: <input type="text" name="description" value="FileField test" maxlength="50" /></li>\\n<li>File: Currently: files/filetest.txt<br/>Change: <input type="file" name="file_file" /> <input type="hidden" name="file" value="files/filetest.txt" /></li>'
+>>> required_file_instance.delete()
+
+Bad data test
+>>> filled_required_fileform=TestRequiredFileForm(no_file_form_data)
+>>> filled_required_fileform.is_valid()
+False
+>>> print filled_required_fileform.errors
+<ul class="errorlist"><li>file<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
+>>> TestNotRequiredFileForm = form_for_model(NotRequiredFile)
+>>> filled_not_required_fileform=TestNotRequiredFileForm(no_file_form_data)
+>>> filled_not_required_fileform.is_valid()
+True
+>>> filled_not_required_fileform=TestNotRequiredFileForm(bad_encoding_form_data)
+>>> print filled_not_required_fileform.errors
+<ul class="errorlist"><li>file<ul class="errorlist"><li>No file was submitted. Check the encoding type on the form.</li></ul></li></ul>
+>>> filled_not_required_fileform=TestNotRequiredFileForm(just_path_form_data)
+>>> filled_not_required_fileform.is_valid()
+True
+>>> filled_required_fileform=TestRequiredFileForm(just_path_form_data)
+>>> filled_required_fileform.is_valid()
+True
 None
 >>> f.clean('')
 >>> f.clean('1')
Index: tests/regressiontests/forms/tests.py
===================================================================
--- tests/regressiontests/forms/tests.py	(revision 4722)
+++ tests/regressiontests/forms/tests.py	(working copy)
@@ -165,27 +165,11 @@
 # FileInput Widget ############################################################
 
 >>> w = FileInput()
->>> w.render('email', '')
-u'<input type="file" name="email" />'
->>> w.render('email', None)
-u'<input type="file" name="email" />'
->>> w.render('email', 'test@example.com')
-u'<input type="file" name="email" value="test@example.com" />'
->>> w.render('email', 'some "quoted" & ampersanded value')
-u'<input type="file" name="email" value="some &quot;quoted&quot; &amp; ampersanded value" />'
->>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
-u'<input type="file" name="email" value="test@example.com" class="fun" />'
+>>> w.render('file', '')
+u'<input type="file" name="file_file" />'
+>>> w.render('file', 'file/filetest.txt')
+u'Currently: file/filetest.txt<br/>Change: <input type="file" name="file_file" /> <input type="hidden" name="file" value="file/filetest.txt" />'
 
-You can also pass 'attrs' to the constructor:
->>> w = FileInput(attrs={'class': 'fun'})
->>> w.render('email', '')
-u'<input type="file" class="fun" name="email" />'
->>> w.render('email', 'foo@example.com')
-u'<input type="file" class="fun" value="foo@example.com" name="email" />'
-
->>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
-u'<input type="file" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
-
 # Textarea Widget #############################################################
 
 >>> w = Textarea()
