diff --git a/django/http/__init__.py b/django/http/__init__.py
index 49acd57..d609eb5 100644
|
a
|
b
|
class HttpResponse(HttpResponseBase):
|
| 751 | 751 | else: |
| 752 | 752 | __str__ = serialize |
| 753 | 753 | |
| | 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 | |
| 754 | 762 | @property |
| 755 | 763 | def content(self): |
| | 764 | self._consume_content() |
| 756 | 765 | return b''.join(self.make_bytes(e) for e in self._container) |
| 757 | 766 | |
| 758 | 767 | @content.setter |
| 759 | 768 | def content(self, value): |
| 760 | 769 | if hasattr(value, '__iter__') and not isinstance(value, (bytes, six.string_types)): |
| 761 | 770 | self._container = value |
| 762 | | self._base_content_is_iter = True |
| 763 | 771 | if hasattr(value, 'close'): |
| 764 | 772 | self._closable_objects.append(value) |
| 765 | 773 | else: |
| 766 | 774 | self._container = [value] |
| 767 | | self._base_content_is_iter = False |
| 768 | 775 | |
| 769 | 776 | def __iter__(self): |
| 770 | 777 | self._iterator = iter(self._container) |
| … |
… |
class HttpResponse(HttpResponseBase):
|
| 782 | 789 | next = __next__ # Python 2 compatibility |
| 783 | 790 | |
| 784 | 791 | 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() |
| 787 | 793 | self._container.append(content) |
| 788 | 794 | |
| 789 | 795 | 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) |
| 793 | 798 | |
| 794 | 799 | class StreamingHttpResponse(HttpResponseBase): |
| 795 | 800 | """ |
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.
|
| 578 | 578 | If you want to guarantee that your response will stream to the client, you |
| 579 | 579 | should use the new :class:`StreamingHttpResponse` class instead. |
| 580 | 580 | |
| 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. |
| 584 | 586 | |
| 585 | 587 | Setting headers |
| 586 | 588 | ~~~~~~~~~~~~~~~ |
diff --git a/tests/regressiontests/httpwrappers/tests.py b/tests/regressiontests/httpwrappers/tests.py
index bfb4ae1..5de4c15 100644
|
a
|
b
|
class HttpResponseTests(unittest.TestCase):
|
| 330 | 330 | self.assertRaises(UnicodeEncodeError, |
| 331 | 331 | getattr, r, 'content') |
| 332 | 332 | |
| | 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 | |
| 333 | 343 | def test_file_interface(self): |
| 334 | 344 | r = HttpResponse() |
| 335 | 345 | r.write(b"hello") |
| … |
… |
class HttpResponseTests(unittest.TestCase):
|
| 338 | 348 | self.assertEqual(r.tell(), 17) |
| 339 | 349 | |
| 340 | 350 | 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') |
| 342 | 354 | |
| 343 | 355 | def test_unsafe_redirect(self): |
| 344 | 356 | bad_urls = [ |