diff --git a/AUTHORS b/AUTHORS index c965ddee4e..19cc277f37 100644 --- a/AUTHORS +++ b/AUTHORS @@ -121,6 +121,7 @@ answer newbie questions, and generally made Django that much better: Matt Dennenbaum deric@monowerks.com Max Derkachev + John DeRosa Rajesh Dhawan Sander Dijkhuis Jordan Dimov diff --git a/django/http/__init__.py b/django/http/__init__.py index d0303639b6..4da8ce5d9e 100644 --- a/django/http/__init__.py +++ b/django/http/__init__.py @@ -275,7 +275,7 @@ class HttpResponse(object): _charset = settings.DEFAULT_CHARSET def __init__(self, content='', mimetype=None, status=None, - content_type=None, request=None): + content_type=None, request=None): from django.conf import settings accept_charset = None if mimetype: @@ -288,16 +288,12 @@ class HttpResponse(object): if not content_type: content_type = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE, self._charset) - if not isinstance(content, basestring) and hasattr(content, '__iter__'): - self._container = content - self._is_string = False - else: - self._container = [content] - self._is_string = True + self._container = [''.join(content)] + if hasattr(content, 'close'): + content.close() self.cookies = SimpleCookie() if status: self.status_code = status - # _headers is a mapping of the lower-case name to the original case of # the header (required for working with legacy systems) and the header # value. @@ -305,9 +301,8 @@ class HttpResponse(object): def __str__(self): """Full HTTP message, including headers.""" - return '\n'.join(['%s: %s' % (key, value) - for key, value in self._headers.values()]) \ - + '\n\n' + self.content + headers = ['%s: %s' % (k, v) for k, v in self._headers.values()] + return '\n'.join(headers) + '\n\n' + self.content def _convert_to_ascii(self, *values): """Converts all values to ascii strings.""" @@ -402,8 +397,7 @@ class HttpResponse(object): return smart_str(''.join(self._container), self._codec.name) def _set_content(self, value): - self._container = [value] - self._is_string = True + self._container = [''.join(value)] content = property(_get_content, _set_content) @@ -420,22 +414,18 @@ class HttpResponse(object): return str(chunk) def close(self): - if hasattr(self._container, 'close'): - self._container.close() + "No-op that remains for backwards compatibility. Ref #6527" + pass # The remaining methods partially implement the file-like object interface. # See http://docs.python.org/lib/bltin-file-objects.html def write(self, content): - if not self._is_string: - raise Exception("This %s instance is not writable" % self.__class__) self._container.append(content) def flush(self): pass def tell(self): - if not self._is_string: - raise Exception("This %s instance cannot tell its position" % self.__class__) return sum([len(chunk) for chunk in self._container]) class HttpResponseSendFile(HttpResponse): diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt index 881d278a55..65e97bf758 100644 --- a/docs/ref/request-response.txt +++ b/docs/ref/request-response.txt @@ -430,12 +430,10 @@ Passing iterators ~~~~~~~~~~~~~~~~~ Finally, you can pass ``HttpResponse`` an iterator rather than passing it -hard-coded strings. If you use this technique, follow these guidelines: +hard-coded strings. If you use this technique, note the following: * The iterator should return strings. - * If an :class:`HttpResponse` has been initialized with an iterator as its - content, you can't use the class:`HttpResponse` instance as a file-like - object. Doing so will raise ``Exception``. + * ``HttpResponse.__init__()`` will read and store the iterator's contents. Setting headers ~~~~~~~~~~~~~~~ diff --git a/tests/regressiontests/httpwrappers/helloworld.txt b/tests/regressiontests/httpwrappers/helloworld.txt new file mode 100644 index 0000000000..18249f3355 --- /dev/null +++ b/tests/regressiontests/httpwrappers/helloworld.txt @@ -0,0 +1 @@ +Hello world. diff --git a/tests/regressiontests/httpwrappers/tests.py b/tests/regressiontests/httpwrappers/tests.py index 04099be16e..95b948ed9b 100644 --- a/tests/regressiontests/httpwrappers/tests.py +++ b/tests/regressiontests/httpwrappers/tests.py @@ -463,6 +463,45 @@ BadHeaderError: Header values can't contain newlines (got 'test\\nstr') >>> x.update(y) >>> x.getlist('a') [u'1', u'2', u'3', u'4'] + +###################################### +# HttpResponse with iterable content # +###################################### + +>>> from django.http import HttpResponse +>>> response = HttpResponse(file('regressiontests/httpwrappers/helloworld.txt','r')) +>>> print response +Content-Type: text/html; charset=utf-8 + +Hello world. + + +>>> print response +Content-Type: text/html; charset=utf-8 + +Hello world. + + +>>> print response +Content-Type: text/html; charset=utf-8 + +Hello world. + + +>>> response = HttpResponse("abc") +>>> print response +Content-Type: text/html; charset=utf-8 + +abc +>>> print response +Content-Type: text/html; charset=utf-8 + +abc +>>> print response +Content-Type: text/html; charset=utf-8 + +abc + """ from django.http import QueryDict, HttpResponse