Ticket #6527: 6527-v3.patch

File 6527-v3.patch, 4.0 KB (added by Aymeric Augustin, 7 years ago)
  • django/http/__init__.py

    diff --git a/django/http/__init__.py b/django/http/__init__.py
    index 49acd57..d609eb5 100644
    a b class HttpResponse(HttpResponseBase): 
    751751    else:
    752752        __str__ = serialize
    753753
     754    def _consume_content(self):
     755        # If the response was instantiated with an iterator, and its content
     756        # is accessed, the iterator is going be exhausted and the content
     757        # loaded in memory. At this point, it's better to abandon the original
     758        # iterator and save the content for later reuse.
     759        if not isinstance(self._container, list):
     760            self._container = list(self._container)
     761
    754762    @property
    755763    def content(self):
     764        self._consume_content()
    756765        return b''.join(self.make_bytes(e) for e in self._container)
    757766
    758767    @content.setter
    759768    def content(self, value):
    760769        if hasattr(value, '__iter__') and not isinstance(value, (bytes, six.string_types)):
    761770            self._container = value
    762             self._base_content_is_iter = True
    763771            if hasattr(value, 'close'):
    764772                self._closable_objects.append(value)
    765773        else:
    766774            self._container = [value]
    767             self._base_content_is_iter = False
    768775
    769776    def __iter__(self):
    770777        self._iterator = iter(self._container)
    class HttpResponse(HttpResponseBase): 
    782789    next = __next__             # Python 2 compatibility
    783790
    784791    def write(self, content):
    785         if self._base_content_is_iter:
    786             raise Exception("This %s instance is not writable" % self.__class__.__name__)
     792        self._consume_content()
    787793        self._container.append(content)
    788794
    789795    def tell(self):
    790         if self._base_content_is_iter:
    791             raise Exception("This %s instance cannot tell its position" % self.__class__.__name__)
    792         return sum([len(chunk) for chunk in self])
     796        self._consume_content()
     797        return sum(len(chunk) for chunk in self)
    793798
    794799class StreamingHttpResponse(HttpResponseBase):
    795800    """
  • docs/ref/request-response.txt

    diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt
    index 89d0fe8..6dda15e 100644
    a b use this technique, the iterator should return strings. 
    578578    If you want to guarantee that your response will stream to the client, you
    579579    should use the new :class:`StreamingHttpResponse` class instead.
    580580
    581 If an :class:`HttpResponse` instance has been initialized with an iterator as
    582 its content, you can't use it as a file-like object. Doing so will raise an
    583 exception.
     581.. versionchanged:: 1.5
     582
     583    You can now use :class:`HttpResponse` as a file-like object even if it was
     584    instantiated with an iterator. Django will consume and save the content of
     585    the iterator on first access.
    584586
    585587Setting headers
    586588~~~~~~~~~~~~~~~
  • tests/regressiontests/httpwrappers/tests.py

    diff --git a/tests/regressiontests/httpwrappers/tests.py b/tests/regressiontests/httpwrappers/tests.py
    index bfb4ae1..5de4c15 100644
    a b class HttpResponseTests(unittest.TestCase): 
    330330        self.assertRaises(UnicodeEncodeError,
    331331                          getattr, r, 'content')
    332332
     333        # content can safely be accessed multiple times.
     334        r = HttpResponse(iter(['hello', 'world']))
     335        self.assertEqual(r.content, r.content)
     336        self.assertEqual(r.content, b'helloworld')
     337
     338        # additional content can be written to the response.
     339        r.write('!')
     340        self.assertEqual(r.content, b'helloworld!')
     341
     342
    333343    def test_file_interface(self):
    334344        r = HttpResponse()
    335345        r.write(b"hello")
    class HttpResponseTests(unittest.TestCase): 
    338348        self.assertEqual(r.tell(), 17)
    339349
    340350        r = HttpResponse(['abc'])
    341         self.assertRaises(Exception, r.write, 'def')
     351        r.write('def')
     352        self.assertEqual(r.tell(), 6)
     353        self.assertEqual(r.content, b'abcdef')
    342354
    343355    def test_unsafe_redirect(self):
    344356        bad_urls = [
Back to Top