Index: django/oldforms/__init__.py
===================================================================
--- django/oldforms/__init__.py	(revision 7340)
+++ django/oldforms/__init__.py	(working copy)
@@ -680,18 +680,23 @@
         self.field_name, self.is_required = field_name, is_required
         self.validator_list = [self.isNonEmptyFile] + validator_list
 
-    def isNonEmptyFile(self, field_data, all_data):
-        try:
-            content = field_data['content']
-        except TypeError:
-            raise validators.CriticalValidationError, ugettext("No file was submitted. Check the encoding type on the form.")
-        if not content:
+    def isNonEmptyFile(self, new_data, all_data):
+        if hasattr(new_data, 'upload_errors'):
+            upload_errors = new_data.upload_errors()
+            if upload_errors:
+                raise validators.CriticalValidationError, upload_errors
+        if not new_data.file_size:
             raise validators.CriticalValidationError, ugettext("The submitted file is empty.")
 
     def render(self, data):
         return mark_safe(u'<input type="file" id="%s" class="v%s" name="%s" />' % \
             (self.get_id(), self.__class__.__name__, self.field_name))
 
+    def prepare(self, new_data):
+        if hasattr(new_data, 'upload_errors'):
+            upload_errors = new_data.upload_errors()
+            new_data[self.field_name] = { '_file_upload_error': upload_errors }
+
     def html2python(data):
         if data is None:
             raise EmptyValue
Index: django/db/models/base.py
===================================================================
--- django/db/models/base.py	(revision 7340)
+++ django/db/models/base.py	(working copy)
@@ -13,6 +13,7 @@
 from django.utils.datastructures import SortedDict
 from django.utils.functional import curry
 from django.utils.encoding import smart_str, force_unicode, smart_unicode
+from django.core.files.filemove import file_move_safe
 from django.conf import settings
 from itertools import izip
 import types
@@ -384,12 +385,16 @@
     def _get_FIELD_size(self, field):
         return os.path.getsize(self._get_FIELD_filename(field))
 
-    def _save_FIELD_file(self, field, filename, raw_contents, save=True):
+    def _save_FIELD_file(self, field, filename, raw_field, save=True):
         directory = field.get_directory_name()
         try: # Create the date-based directory if it doesn't exist.
             os.makedirs(os.path.join(settings.MEDIA_ROOT, directory))
         except OSError: # Directory probably already exists.
             pass
+
+        if filename is None:
+            filename = raw_field.file_name
+
         filename = field.get_filename(filename)
 
         # If the filename already exists, keep adding an underscore to the name of
@@ -406,9 +411,18 @@
         setattr(self, field.attname, filename)
 
         full_filename = self._get_FIELD_filename(field)
-        fp = open(full_filename, 'wb')
-        fp.write(raw_contents)
-        fp.close()
+        if hasattr(raw_field, 'temporary_file_path'):
+            raw_field.close()
+            file_move_safe(raw_field.temporary_file_path(), full_filename)
+        else:
+            from django.utils import file_locks
+            fp = open(full_filename, 'wb')
+            # exclusive lock
+            file_locks.lock(fp, file_locks.LOCK_EX)
+            # Stream it into the file, from where it is.
+            for chunk in raw_field.chunk(65535):
+                fp.write(chunk)
+            fp.close()
 
         # Save the width and/or height, if applicable.
         if isinstance(field, ImageField) and (field.width_field or field.height_field):
Index: django/db/models/fields/__init__.py
===================================================================
--- django/db/models/fields/__init__.py	(revision 7340)
+++ django/db/models/fields/__init__.py	(working copy)
@@ -785,7 +785,8 @@
         setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self))
         setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self))
         setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self))
-        setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_contents, save=True: instance._save_FIELD_file(self, filename, raw_contents, save))
+        setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_field, save=True: instance._save_FIELD_file(self, filename, raw_field, save))
+        setattr(cls, 'move_%s_file' % self.name, lambda instance, raw_field, save=True: instance._save_FIELD_file(self, None, raw_field, save))
         dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)
 
     def delete_file(self, instance):
@@ -808,9 +809,9 @@
         if 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)
+                func(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0], save)
             else:
-                func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"], save)
+                func(new_data[upload_field_name]["filename"], new_data[upload_field_name], save)
 
     def get_directory_name(self):
         return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
@@ -823,7 +824,7 @@
     def save_form_data(self, instance, data):
         from django.newforms.fields import UploadedFile
         if data and isinstance(data, UploadedFile):
-            getattr(instance, "save_%s_file" % self.name)(data.filename, data.content, save=False)
+            getattr(instance, "save_%s_file" % self.name)(data.filename, data.data, save=False)
 
     def formfield(self, **kwargs):
         defaults = {'form_class': forms.FileField}
Index: django/core/files/filelocks.py
===================================================================
--- django/core/files/filelocks.py	(revision 0)
+++ django/core/files/filelocks.py	(revision 0)
@@ -0,0 +1,50 @@
+"""
+Locking portability by Jonathan Feignberg <jdf@pobox.com> in python cookbook
+
+Example Usage::
+
+    from django.utils import file_locks
+
+    f = open('./file', 'wb')
+
+    file_locks.lock(f, file_locks.LOCK_EX)
+    f.write('Django')
+    f.close()
+"""
+
+
+import os
+
+__all__ = ['LOCK_EX','LOCK_SH','LOCK_NB','lock','unlock']
+
+if os.name == 'nt':
+	import win32con
+	import win32file
+	import pywintypes
+	LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
+	LOCK_SH = 0
+	LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
+	__overlapped = pywintypes.OVERLAPPED()
+elif os.name == 'posix':
+	import fcntl
+	LOCK_EX = fcntl.LOCK_EX
+	LOCK_SH = fcntl.LOCK_SH
+	LOCK_NB = fcntl.LOCK_NB
+else:
+	raise RuntimeError("Locking only defined for nt and posix platforms")
+
+if os.name == 'nt':
+	def lock(file, flags):
+		hfile = win32file._get_osfhandle(file.fileno())
+		win32file.LockFileEx(hfile, flags, 0, -0x10000, __overlapped)
+
+	def unlock(file):
+		hfile = win32file._get_osfhandle(file.fileno())
+		win32file.UnlockFileEx(hfile, 0, -0x10000, __overlapped)
+
+elif os.name =='posix':
+	def lock(file, flags):
+		fcntl.flock(file.fileno(), flags)
+
+	def unlock(file):
+		fcntl.flock(file.fileno(), fcntl.LOCK_UN)
Index: django/core/files/__init__.py
===================================================================
Index: django/core/files/filemove.py
===================================================================
--- django/core/files/filemove.py	(revision 0)
+++ django/core/files/filemove.py	(revision 0)
@@ -0,0 +1,53 @@
+import os
+
+__all__ = ('file_move_safe',)
+
+try:
+    import shutil
+    file_move = shutil.move
+except ImportError:
+    file_move = os.rename
+
+def file_move_safe(old_file_name, new_file_name, chunk_size = 1024*64, allow_overwrite=False):
+    """
+    Moves a file from one location to another in the safest way possible.
+    
+    First, it tries using shutils.move, which is OS-dependent but doesn't
+    break with change of filesystems. Then it tries os.rename, which will
+    break if it encounters a change in filesystems. Lastly, it streams
+    it manually from one file to another in python.
+
+    Without ``allow_overwrite``, if the destination file exists, the
+    file will raise an IOError.
+    """
+
+    from django.core.files import filelocks
+
+    if old_file_name == new_file_name:
+        # No file moving takes place.
+        return
+
+    if not allow_overwrite and os.path.exists(new_file_name):
+        raise IOError, "Django does not allow overwriting files."
+
+    try:
+        file_move(old_file_name, new_file_name)
+        return
+    except OSError: # moving to another filesystem
+        pass
+
+    new_file = open(new_file_name, 'wb')
+    # exclusive lock
+    filelocks.lock(new_file, filelocks.LOCK_EX)
+    old_file = open(old_file_name, 'rb')
+    current_chunk = None
+
+    while current_chunk != '':
+        current_chunk = old_file.read(chunk_size)
+        new_file.write(current_chunk)
+
+    new_file.close()
+    old_file.close()
+
+    os.remove(old_file_name)
+
Index: django/newforms/fields.py
===================================================================
--- django/newforms/fields.py	(revision 7340)
+++ django/newforms/fields.py	(working copy)
@@ -416,9 +416,9 @@
 
 class UploadedFile(StrAndUnicode):
     "A wrapper for files uploaded in a FileField"
-    def __init__(self, filename, content):
+    def __init__(self, filename, data):
         self.filename = filename
-        self.content = content
+        self.data = data
 
     def __unicode__(self):
         """
@@ -445,12 +445,12 @@
         elif not data and initial:
             return initial
         try:
-            f = UploadedFile(data['filename'], data['content'])
+            f = UploadedFile(data['filename'], data)
         except TypeError:
             raise ValidationError(self.error_messages['invalid'])
         except KeyError:
             raise ValidationError(self.error_messages['missing'])
-        if not f.content:
+        if not f.data.file_size:
             raise ValidationError(self.error_messages['empty'])
         return f
 
@@ -470,15 +470,26 @@
         elif not data and initial:
             return initial
         from PIL import Image
-        from cStringIO import StringIO
+
+        # We need to get the file, it either has a path
+        # or we have to read it all into memory...
+        if hasattr(data, 'temporary_file_path'):
+            file = data.temporary_file_path()
+        else:
+            try:
+                from cStringIO import StringIO
+            except ImportError:
+                from StringIO import StringIO
+            file = StringIO(data.read())
+
         try:
             # load() is the only method that can spot a truncated JPEG,
             #  but it cannot be called sanely after verify()
-            trial_image = Image.open(StringIO(f.content))
+            trial_image = Image.open(file)
             trial_image.load()
             # verify() is the only method that can spot a corrupt PNG,
             #  but it must be called immediately after the constructor
-            trial_image = Image.open(StringIO(f.content))
+            trial_image = Image.open(file)
             trial_image.verify()
         except Exception: # Python Imaging Library doesn't recognize it as an image
             raise ValidationError(self.error_messages['invalid_image'])
