2
0
Эх сурвалжийг харах

Fixed #15644 -- Improved Django File wrapper to support more file-like objects. Thanks nickname123 and Michael Palumbo for working on the patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17871 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Claude Paroz 13 жил өмнө
parent
commit
5c954136ea

+ 11 - 6
django/core/files/base.py

@@ -36,8 +36,13 @@ class File(FileProxyMixin):
         if not hasattr(self, '_size'):
             if hasattr(self.file, 'size'):
                 self._size = self.file.size
-            elif os.path.exists(self.file.name):
+            elif hasattr(self.file, 'name') and os.path.exists(self.file.name):
                 self._size = os.path.getsize(self.file.name)
+            elif hasattr(self.file, 'tell') and hasattr(self.file, 'seek'):
+                pos = self.file.tell()
+                self.file.seek(0, os.SEEK_END)
+                self._size = self.file.tell()
+                self.file.seek(pos)
             else:
                 raise AttributeError("Unable to determine the file's size.")
         return self._size
@@ -61,12 +66,12 @@ class File(FileProxyMixin):
 
         if hasattr(self, 'seek'):
             self.seek(0)
-        # Assume the pointer is at zero...
-        counter = self.size
 
-        while counter > 0:
-            yield self.read(chunk_size)
-            counter -= chunk_size
+        while True:
+            data = self.read(chunk_size)
+            if not data:
+                break
+            yield data
 
     def multiple_chunks(self, chunk_size=None):
         """

+ 41 - 2
tests/regressiontests/file_storage/tests.py

@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
 import errno
 import os
 import shutil
@@ -17,12 +19,13 @@ except ImportError:
 
 from django.conf import settings
 from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured
-from django.core.files.base import ContentFile
+from django.core.files.base import File, ContentFile
 from django.core.files.images import get_image_dimensions
 from django.core.files.storage import FileSystemStorage, get_storage_class
 from django.core.files.uploadedfile import UploadedFile
 from django.test import SimpleTestCase
 from django.utils import unittest
+from ..servers.tests import LiveServerBase
 
 # Try to import PIL in either of the two ways it can end up installed.
 # Checking for the existence of Image is enough for CPython, but
@@ -544,6 +547,42 @@ class ContentFileTestCase(unittest.TestCase):
     def test_content_file_default_name(self):
         self.assertEqual(ContentFile("content").name, None)
 
-    def test_content_file_custome_name(self):
+    def test_content_file_custom_name(self):
         name = "I can have a name too!"
         self.assertEqual(ContentFile("content", name=name).name, name)
+
+class NoNameFileTestCase(unittest.TestCase):
+    """
+    Other examples of unnamed files may be tempfile.SpooledTemporaryFile or
+    urllib.urlopen()
+    """
+    def test_noname_file_default_name(self):
+        self.assertEqual(File(StringIO('A file with no name')).name, None)
+
+    def test_noname_file_get_size(self):
+        self.assertEqual(File(StringIO('A file with no name')).size, 19)
+
+class FileLikeObjectTestCase(LiveServerBase):
+    """
+    Test file-like objects (#15644).
+    """
+    def setUp(self):
+        self.temp_dir = tempfile.mkdtemp()
+        self.storage = FileSystemStorage(location=self.temp_dir)
+
+    def tearDown(self):
+        shutil.rmtree(self.temp_dir)
+
+    def test_urllib2_urlopen(self):
+        """
+        Test the File storage API with a file like object coming from urllib2.urlopen()
+        """
+
+        file_like_object = self.urlopen('/example_view/')
+        f = File(file_like_object)
+        stored_filename = self.storage.save("remote_file.html", f)
+
+        stored_file = self.storage.open(stored_filename)
+        remote_file = self.urlopen('/example_view/')
+
+        self.assertEqual(stored_file.read(), remote_file.read())