mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #35727 -- Added HttpResponse.text property.
Signed-off-by: SaJH <wogur981208@gmail.com>
This commit is contained in:
		| @@ -21,6 +21,7 @@ from django.http.cookie import SimpleCookie | |||||||
| from django.utils import timezone | from django.utils import timezone | ||||||
| from django.utils.datastructures import CaseInsensitiveMapping | from django.utils.datastructures import CaseInsensitiveMapping | ||||||
| from django.utils.encoding import iri_to_uri | from django.utils.encoding import iri_to_uri | ||||||
|  | from django.utils.functional import cached_property | ||||||
| from django.utils.http import content_disposition_header, http_date | from django.utils.http import content_disposition_header, http_date | ||||||
| from django.utils.regex_helper import _lazy_re_compile | from django.utils.regex_helper import _lazy_re_compile | ||||||
|  |  | ||||||
| @@ -408,6 +409,11 @@ class HttpResponse(HttpResponseBase): | |||||||
|             content = self.make_bytes(value) |             content = self.make_bytes(value) | ||||||
|         # Create a list of properly encoded bytestrings to support write(). |         # Create a list of properly encoded bytestrings to support write(). | ||||||
|         self._container = [content] |         self._container = [content] | ||||||
|  |         self.__dict__.pop("text", None) | ||||||
|  |  | ||||||
|  |     @cached_property | ||||||
|  |     def text(self): | ||||||
|  |         return self.content.decode(self.charset or "utf-8") | ||||||
|  |  | ||||||
|     def __iter__(self): |     def __iter__(self): | ||||||
|         return iter(self._container) |         return iter(self._container) | ||||||
| @@ -460,6 +466,12 @@ class StreamingHttpResponse(HttpResponseBase): | |||||||
|             "`streaming_content` instead." % self.__class__.__name__ |             "`streaming_content` instead." % self.__class__.__name__ | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def text(self): | ||||||
|  |         raise AttributeError( | ||||||
|  |             "This %s instance has no `text` attribute." % self.__class__.__name__ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def streaming_content(self): |     def streaming_content(self): | ||||||
|         if self.is_async: |         if self.is_async: | ||||||
|   | |||||||
| @@ -833,6 +833,13 @@ Attributes | |||||||
|  |  | ||||||
|     A bytestring representing the content, encoded from a string if necessary. |     A bytestring representing the content, encoded from a string if necessary. | ||||||
|  |  | ||||||
|  | .. attribute:: HttpResponse.text | ||||||
|  |  | ||||||
|  |     .. versionadded:: 5.2 | ||||||
|  |  | ||||||
|  |     A string representation of :attr:`HttpResponse.content`, decoded using the | ||||||
|  |     response's :attr:`HttpResponse.charset` (defaulting to ``UTF-8`` if empty). | ||||||
|  |  | ||||||
| .. attribute:: HttpResponse.cookies | .. attribute:: HttpResponse.cookies | ||||||
|  |  | ||||||
|     A :py:obj:`http.cookies.SimpleCookie` object holding the cookies included |     A :py:obj:`http.cookies.SimpleCookie` object holding the cookies included | ||||||
| @@ -1272,6 +1279,9 @@ with the following notable differences: | |||||||
|   :attr:`~StreamingHttpResponse.streaming_content` attribute. This can be used |   :attr:`~StreamingHttpResponse.streaming_content` attribute. This can be used | ||||||
|   in middleware to wrap the response iterable, but should not be consumed. |   in middleware to wrap the response iterable, but should not be consumed. | ||||||
|  |  | ||||||
|  | * It has no ``text`` attribute, as it would require iterating the response | ||||||
|  |   object. | ||||||
|  |  | ||||||
| * You cannot use the file-like object ``tell()`` or ``write()`` methods. | * You cannot use the file-like object ``tell()`` or ``write()`` methods. | ||||||
|   Doing so will raise an exception. |   Doing so will raise an exception. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -268,6 +268,9 @@ Models | |||||||
| Requests and Responses | Requests and Responses | ||||||
| ~~~~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |  | ||||||
|  | * The new :attr:`.HttpResponse.text` property provides the string representation | ||||||
|  |   of :attr:`.HttpResponse.content`. | ||||||
|  |  | ||||||
| * The new :meth:`.HttpRequest.get_preferred_type` method can be used to query | * The new :meth:`.HttpRequest.get_preferred_type` method can be used to query | ||||||
|   the preferred media type the client accepts. |   the preferred media type the client accepts. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -530,6 +530,22 @@ class HttpResponseTests(SimpleTestCase): | |||||||
|                 headers={"Content-Type": "text/csv"}, |                 headers={"Content-Type": "text/csv"}, | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|  |     def test_text_updates_when_content_updates(self): | ||||||
|  |         response = HttpResponse("Hello, world!") | ||||||
|  |         self.assertEqual(response.text, "Hello, world!") | ||||||
|  |         response.content = "Updated content" | ||||||
|  |         self.assertEqual(response.text, "Updated content") | ||||||
|  |  | ||||||
|  |     def test_text_charset(self): | ||||||
|  |         for content_type, content in [ | ||||||
|  |             (None, b"Ol\xc3\xa1 Mundo"), | ||||||
|  |             ("text/plain; charset=utf-8", b"Ol\xc3\xa1 Mundo"), | ||||||
|  |             ("text/plain; charset=iso-8859-1", b"Ol\xe1 Mundo"), | ||||||
|  |         ]: | ||||||
|  |             with self.subTest(content_type=content_type): | ||||||
|  |                 response = HttpResponse(content, content_type=content_type) | ||||||
|  |                 self.assertEqual(response.text, "Olá Mundo") | ||||||
|  |  | ||||||
|  |  | ||||||
| class HttpResponseSubclassesTests(SimpleTestCase): | class HttpResponseSubclassesTests(SimpleTestCase): | ||||||
|     def test_redirect(self): |     def test_redirect(self): | ||||||
| @@ -756,6 +772,13 @@ class StreamingHttpResponseTests(SimpleTestCase): | |||||||
|         with self.assertWarnsMessage(Warning, msg): |         with self.assertWarnsMessage(Warning, msg): | ||||||
|             self.assertEqual(b"hello", await anext(aiter(r))) |             self.assertEqual(b"hello", await anext(aiter(r))) | ||||||
|  |  | ||||||
|  |     def test_text_attribute_error(self): | ||||||
|  |         r = StreamingHttpResponse(iter(["hello", "world"])) | ||||||
|  |         msg = "This %s instance has no `text` attribute." % r.__class__.__name__ | ||||||
|  |  | ||||||
|  |         with self.assertRaisesMessage(AttributeError, msg): | ||||||
|  |             r.text | ||||||
|  |  | ||||||
|  |  | ||||||
| class FileCloseTests(SimpleTestCase): | class FileCloseTests(SimpleTestCase): | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user