Index: db/models/manipulators.py
===================================================================
--- db/models/manipulators.py	(revision 6635)
+++ db/models/manipulators.py	(working copy)
@@ -170,9 +170,9 @@
                                 pass
 
                     for f in related.opts.fields:
-                        if f.core and not isinstance(f, FileField) and f.get_manipulator_new_data(rel_new_data, rel=True) in (None, ''):
+                        if f.core and f.get_manipulator_new_data(rel_new_data, rel=True) in (None, ''):
                             all_cores_given = False
-                        elif f.core and not isinstance(f, FileField) and f.get_manipulator_new_data(rel_new_data, rel=True) not in (None, ''):
+                        elif f.core and f.get_manipulator_new_data(rel_new_data, rel=True) not in (None, ''):
                             all_cores_blank = False
                         # If this field isn't editable, give it the same value it had
                         # previously, according to the given ID. If the ID wasn't
Index: db/models/fields/__init__.py
===================================================================
--- db/models/fields/__init__.py	(revision 6635)
+++ db/models/fields/__init__.py	(working copy)
@@ -706,10 +706,12 @@
         return super(EmailField, self).formfield(**defaults)
 
 class FileField(Field):
-    def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
+    def __init__(self, verbose_name=None, name=None, upload_to='', can_delete=False, **kwargs):
         self.upload_to = upload_to
+        self.can_delete = can_delete
         kwargs['max_length'] = kwargs.get('max_length', 100)        
         Field.__init__(self, verbose_name, name, **kwargs)
+        assert (not self.can_delete) or self.null, "A FileField must have null=True if can_delete=True"
 
     def get_db_prep_save(self, value):
         "Returns field's value prepared for saving into a database."
@@ -718,6 +720,23 @@
             return None
         return unicode(value)
 
+    def get_manipulator_new_data(self, new_data, rel=False):
+        # Return the value which the field will take, if it is saved.
+        # This will be either the pathname of the uploaded file, or the
+        # pathname of the existing file, if no file was uploaded.
+        if rel:
+            extract = lambda field: (new_data.get("%s%s" % (self.name, field), [None])[0])
+        else:
+            extract = lambda field: (new_data.get("%s%s" % (self.name, field), None))
+        if extract('_delete'):
+            return None
+        try:
+            file = extract('_file')
+            return self.get_filename(file['filename'])
+        except (IndexError, KeyError, TypeError):
+            pass
+        return extract('')
+
     def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
         field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
         if not self.blank:
@@ -772,14 +791,29 @@
                 os.remove(file_name)
 
     def get_manipulator_field_objs(self):
+        if self.can_delete:
+            return [oldforms.FileUploadField, oldforms.HiddenField, oldforms.LabeledCheckbox]
         return [oldforms.FileUploadField, oldforms.HiddenField]
 
     def get_manipulator_field_names(self, name_prefix):
+        if self.can_delete:
+            return [name_prefix + self.name + '_file', name_prefix + self.name, name_prefix + self.name + '_delete']
         return [name_prefix + self.name + '_file', name_prefix + self.name]
 
     def save_file(self, new_data, new_object, original_object, change, rel, save=True):
-        upload_field_name = self.get_manipulator_field_names('')[0]
-        if new_data.get(upload_field_name, False):
+        field_names = self.get_manipulator_field_names('')
+        upload_field_name = field_names[0]
+        # Delete only if delete checkbox is present and checked
+        if self.can_delete and ((rel and new_data.get(field_names[2], [False])[0]) or
+                                (not rel and new_data.get(field_names[2], False))):
+            file_name = getattr(original_object, 'get_%s_filename' % self.name)()
+            # If file exists, delete it
+            if file_name and os.path.exists(file_name):
+                os.remove(file_name)
+            setattr(new_object, self.name, None)
+            new_object.save()
+        elif new_data.get(upload_field_name, False):
+
             func = getattr(new_object, 'save_%s_file' % self.name)
             if rel:
                 func(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"], save)
@@ -833,6 +867,8 @@
         FileField.__init__(self, verbose_name, name, **kwargs)
 
     def get_manipulator_field_objs(self):
+        if self.can_delete:
+            return [oldforms.ImageUploadField, oldforms.HiddenField, oldforms.LabeledCheckbox]
         return [oldforms.ImageUploadField, oldforms.HiddenField]
 
     def contribute_to_class(self, cls, name):
Index: oldforms/__init__.py
===================================================================
--- oldforms/__init__.py	(revision 6635)
+++ oldforms/__init__.py	(working copy)
@@ -1048,3 +1048,31 @@
             v(field_data, all_data)
         except validators.ValidationError, e:
             raise validators.CriticalValidationError, e.messages
+
+
+class LabeledCheckbox(CheckboxField):
+    """
+    A checkbox for which is_required is allowed to be set to False, and
+    which optionally displays a text label before its form control.
+    """
+    def __init__(self, field_name, checked_by_default=False, validator_list=None, is_required=False, label=None, max_length=None):
+        self.label = label
+        # This default is to support using this checkbox as a delete field in
+        # FileField objects. It is only required because there is no easy way
+        # to send unique constructor parameters to multiple manipulator field
+        # objects.
+        if self.label == None:
+            self.label = ugettext("Delete")
+        super(LabeledCheckbox, self).__init__(field_name, checked_by_default, validator_list)
+
+    def render(self, data):
+        checked_html = ''
+        if data or (data is '' and self.checked_by_default):
+            checked_html = ' checked="checked"'
+        label_html = ''
+        if self.label:
+            label_html = "&nbsp;%s&nbsp;" % self.label
+        return '%s<input type="checkbox" id="%s" class="v%s" name="%s"%s value="on" />' % \
+            (label_html, self.get_id(), self.__class__.__name__,
+            self.field_name, checked_html)
+
