Fixed #1569 -- HttpResponse now accepts iterators. Thanks, Maniac
git-svn-id: http://code.djangoproject.com/svn/django/trunk@2639 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
b0a60c186e
commit
bc4638d722
2
AUTHORS
2
AUTHORS
|
@ -73,7 +73,6 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Eugene Lazutkin <http://lazutkin.com/blog/>
|
Eugene Lazutkin <http://lazutkin.com/blog/>
|
||||||
limodou
|
limodou
|
||||||
Martin Maney <http://www.chipy.org/Martin_Maney>
|
Martin Maney <http://www.chipy.org/Martin_Maney>
|
||||||
Maniac <http://www.softwaremaniacs.org/>
|
|
||||||
Manuzhai
|
Manuzhai
|
||||||
Petar Marić
|
Petar Marić
|
||||||
mark@junklight.com
|
mark@junklight.com
|
||||||
|
@ -95,6 +94,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
J. Rademaker
|
J. Rademaker
|
||||||
Brian Ray <http://brianray.chipy.org/>
|
Brian Ray <http://brianray.chipy.org/>
|
||||||
Oliver Rutherfurd <http://rutherfurd.net/>
|
Oliver Rutherfurd <http://rutherfurd.net/>
|
||||||
|
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
||||||
David Schein
|
David Schein
|
||||||
sopel
|
sopel
|
||||||
Radek Švarz <http://www.svarz.cz/translate/>
|
Radek Švarz <http://www.svarz.cz/translate/>
|
||||||
|
|
|
@ -162,7 +162,8 @@ def populate_apache_request(http_response, mod_python_req):
|
||||||
for c in http_response.cookies.values():
|
for c in http_response.cookies.values():
|
||||||
mod_python_req.headers_out.add('Set-Cookie', c.output(header=''))
|
mod_python_req.headers_out.add('Set-Cookie', c.output(header=''))
|
||||||
mod_python_req.status = http_response.status_code
|
mod_python_req.status = http_response.status_code
|
||||||
mod_python_req.write(http_response.get_content_as_string(settings.DEFAULT_CHARSET))
|
for chunk in http_response.iterator:
|
||||||
|
mod_python_req.write(chunk)
|
||||||
|
|
||||||
def handler(req):
|
def handler(req):
|
||||||
# mod_python hooks into this function.
|
# mod_python hooks into this function.
|
||||||
|
|
|
@ -172,6 +172,5 @@ class WSGIHandler(BaseHandler):
|
||||||
response_headers = response.headers.items()
|
response_headers = response.headers.items()
|
||||||
for c in response.cookies.values():
|
for c in response.cookies.values():
|
||||||
response_headers.append(('Set-Cookie', c.output(header='')))
|
response_headers.append(('Set-Cookie', c.output(header='')))
|
||||||
output = [response.get_content_as_string(settings.DEFAULT_CHARSET)]
|
|
||||||
start_response(status, response_headers)
|
start_response(status, response_headers)
|
||||||
return output
|
return response.iterator
|
||||||
|
|
|
@ -67,7 +67,7 @@ class CommonMiddleware:
|
||||||
|
|
||||||
# Use ETags, if requested.
|
# Use ETags, if requested.
|
||||||
if settings.USE_ETAGS:
|
if settings.USE_ETAGS:
|
||||||
etag = md5.new(response.get_content_as_string(settings.DEFAULT_CHARSET)).hexdigest()
|
etag = md5.new(response.content).hexdigest()
|
||||||
if request.META.get('HTTP_IF_NONE_MATCH') == etag:
|
if request.META.get('HTTP_IF_NONE_MATCH') == etag:
|
||||||
response = httpwrappers.HttpResponseNotModified()
|
response = httpwrappers.HttpResponseNotModified()
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -74,7 +74,7 @@ def patch_response_headers(response, cache_timeout=None):
|
||||||
cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
|
cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
|
||||||
now = datetime.datetime.utcnow()
|
now = datetime.datetime.utcnow()
|
||||||
if not response.has_header('ETag'):
|
if not response.has_header('ETag'):
|
||||||
response['ETag'] = md5.new(response.get_content_as_string('utf8')).hexdigest()
|
response['ETag'] = md5.new(response.content).hexdigest()
|
||||||
if not response.has_header('Last-Modified'):
|
if not response.has_header('Last-Modified'):
|
||||||
response['Last-Modified'] = now.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
response['Last-Modified'] = now.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||||
if not response.has_header('Expires'):
|
if not response.has_header('Expires'):
|
||||||
|
|
|
@ -143,14 +143,20 @@ def parse_cookie(cookie):
|
||||||
cookiedict[key] = c.get(key).value
|
cookiedict[key] = c.get(key).value
|
||||||
return cookiedict
|
return cookiedict
|
||||||
|
|
||||||
class HttpResponse:
|
class HttpResponse(object):
|
||||||
"A basic HTTP response, with content and dictionary-accessed headers"
|
"A basic HTTP response, with content and dictionary-accessed headers"
|
||||||
def __init__(self, content='', mimetype=None):
|
def __init__(self, content='', mimetype=None):
|
||||||
|
from django.conf.settings import DEFAULT_CONTENT_TYPE, DEFAULT_CHARSET
|
||||||
|
self._charset = DEFAULT_CHARSET
|
||||||
if not mimetype:
|
if not mimetype:
|
||||||
from django.conf.settings import DEFAULT_CONTENT_TYPE, DEFAULT_CHARSET
|
|
||||||
mimetype = "%s; charset=%s" % (DEFAULT_CONTENT_TYPE, DEFAULT_CHARSET)
|
mimetype = "%s; charset=%s" % (DEFAULT_CONTENT_TYPE, DEFAULT_CHARSET)
|
||||||
self.content = content
|
if hasattr(content, '__iter__'):
|
||||||
self.headers = {'Content-Type':mimetype}
|
self.iterator = content
|
||||||
|
self._is_string = False
|
||||||
|
else:
|
||||||
|
self.iterator = [content]
|
||||||
|
self._is_string = True
|
||||||
|
self.headers = {'Content-Type': mimetype}
|
||||||
self.cookies = SimpleCookie()
|
self.cookies = SimpleCookie()
|
||||||
self.status_code = 200
|
self.status_code = 200
|
||||||
|
|
||||||
|
@ -193,25 +199,32 @@ class HttpResponse:
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_content_as_string(self, encoding):
|
def _get_content(self):
|
||||||
"""
|
content = ''.join(self.iterator)
|
||||||
Returns the content as a string, encoding it from a Unicode object if
|
if isinstance(content, unicode):
|
||||||
necessary.
|
content = content.encode(self._charset)
|
||||||
"""
|
return content
|
||||||
if isinstance(self.content, unicode):
|
|
||||||
return self.content.encode(encoding)
|
def _set_content(self, value):
|
||||||
return self.content
|
self.iterator = [value]
|
||||||
|
self._is_string = True
|
||||||
|
|
||||||
|
content = property(_get_content, _set_content)
|
||||||
|
|
||||||
# The remaining methods partially implement the file-like object interface.
|
# The remaining methods partially implement the file-like object interface.
|
||||||
# See http://docs.python.org/lib/bltin-file-objects.html
|
# See http://docs.python.org/lib/bltin-file-objects.html
|
||||||
def write(self, content):
|
def write(self, content):
|
||||||
self.content += content
|
if not self._is_string:
|
||||||
|
raise Exception, "This %s instance is not writable" % self.__class__
|
||||||
|
self.iterator.append(content)
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def tell(self):
|
def tell(self):
|
||||||
return len(self.content)
|
if not self._is_string:
|
||||||
|
raise Exception, "This %s instance cannot tell its position" % self.__class__
|
||||||
|
return sum(len(chunk) for chunk in self.iterator)
|
||||||
|
|
||||||
class HttpResponseRedirect(HttpResponse):
|
class HttpResponseRedirect(HttpResponse):
|
||||||
def __init__(self, redirect_to):
|
def __init__(self, redirect_to):
|
||||||
|
|
|
@ -304,6 +304,10 @@ Methods
|
||||||
Instantiates an ``HttpResponse`` object with the given page content (a
|
Instantiates an ``HttpResponse`` object with the given page content (a
|
||||||
string) and MIME type. The ``DEFAULT_MIME_TYPE`` is ``"text/html"``.
|
string) and MIME type. The ``DEFAULT_MIME_TYPE`` is ``"text/html"``.
|
||||||
|
|
||||||
|
**New in Django development version:** ``content`` can be an iterator
|
||||||
|
instead of a string. This iterator should return strings, and those strings
|
||||||
|
will be joined together to form the content of the response.
|
||||||
|
|
||||||
``__setitem__(header, value)``
|
``__setitem__(header, value)``
|
||||||
Sets the given header name to the given value. Both ``header`` and
|
Sets the given header name to the given value. Both ``header`` and
|
||||||
``value`` should be strings.
|
``value`` should be strings.
|
||||||
|
@ -341,7 +345,12 @@ Methods
|
||||||
|
|
||||||
``get_content_as_string(encoding)``
|
``get_content_as_string(encoding)``
|
||||||
Returns the content as a Python string, encoding it from a Unicode object
|
Returns the content as a Python string, encoding it from a Unicode object
|
||||||
if necessary.
|
if necessary. **Removed in Django development version.**
|
||||||
|
|
||||||
|
``content``
|
||||||
|
**New in Django development version.** Returns the content as a Python
|
||||||
|
string, encoding it from a Unicode object if necessary. Note this is a
|
||||||
|
property, not a method, so use ``r.content`` instead of ``r.content()``.
|
||||||
|
|
||||||
``write(content)``, ``flush()`` and ``tell()``
|
``write(content)``, ``flush()`` and ``tell()``
|
||||||
These methods make an ``HttpResponse`` instance a file-like object.
|
These methods make an ``HttpResponse`` instance a file-like object.
|
||||||
|
|
Loading…
Reference in New Issue