diff options
| author | Aymeric Augustin <aymeric.augustin@m4x.org> | 2012-10-23 22:25:38 +0200 |
|---|---|---|
| committer | Aymeric Augustin <aymeric.augustin@m4x.org> | 2012-10-24 17:08:37 +0200 |
| commit | 495a8b8107dbd4fb511954bcd2322d125addd94e (patch) | |
| tree | 3d1c7864ec421dc046085d1f8c085335c3c514b3 /django/http | |
| parent | 83041ca8025425530fcd32b50f247077ac0a5b74 (diff) | |
Fixed #6527 -- Provided repeatable content access
in HttpResponses instantiated with iterators.
Diffstat (limited to 'django/http')
| -rw-r--r-- | django/http/response.py | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/django/http/response.py b/django/http/response.py index 4a5c479419..e9cc3f70a9 100644 --- a/django/http/response.py +++ b/django/http/response.py @@ -246,8 +246,18 @@ class HttpResponse(HttpResponseBase): else: __str__ = serialize + def _consume_content(self): + # If the response was instantiated with an iterator, when its content + # is accessed, the iterator is going be exhausted and the content + # loaded in memory. At this point, it's better to abandon the original + # iterator and save the content for later reuse. This is a temporary + # solution. See the comment in __iter__ below for the long term plan. + if self._base_content_is_iter: + self.content = b''.join(self.make_bytes(e) for e in self._container) + @property def content(self): + self._consume_content() return b''.join(self.make_bytes(e) for e in self._container) @content.setter @@ -262,6 +272,17 @@ class HttpResponse(HttpResponseBase): self._base_content_is_iter = False def __iter__(self): + # Raise a deprecation warning only if the content wasn't consumed yet, + # because the response may be intended to be streamed. + # Once the deprecation completes, iterators should be consumed upon + # assignment rather than upon access. The _consume_content method + # should be removed. See #6527. + if self._base_content_is_iter: + warnings.warn( + 'Creating streaming responses with `HttpResponse` is ' + 'deprecated. Use `StreamingHttpResponse` instead ' + 'if you need the streaming behavior.', + PendingDeprecationWarning, stacklevel=2) self._iterator = iter(self._container) return self @@ -277,14 +298,12 @@ class HttpResponse(HttpResponseBase): next = __next__ # Python 2 compatibility def write(self, content): - if self._base_content_is_iter: - raise Exception("This %s instance is not writable" % self.__class__.__name__) + self._consume_content() self._container.append(content) def tell(self): - if self._base_content_is_iter: - raise Exception("This %s instance cannot tell its position" % self.__class__.__name__) - return sum([len(chunk) for chunk in self]) + self._consume_content() + return sum(len(chunk) for chunk in self) class StreamingHttpResponse(HttpResponseBase): @@ -389,6 +408,7 @@ class HttpResponseNotModified(HttpResponse): if value: raise AttributeError("You cannot set content to a 304 (Not Modified) response") self._container = [] + self._base_content_is_iter = False class HttpResponseBadRequest(HttpResponse): |
