diff --git a/django/utils/html.py b/django/utils/html.py index 75eff0083d..825f139070 100644 --- a/django/utils/html.py +++ b/django/utils/html.py @@ -65,8 +65,8 @@ def conditional_escape(text): """ Similar to escape(), except that it doesn't operate on pre-escaped strings. """ - if isinstance(text, SafeData): - return text + if hasattr(text, '__html__'): + return text.__html__() else: return escape(text) diff --git a/django/utils/safestring.py b/django/utils/safestring.py index bec59385f7..aee6427b3c 100644 --- a/django/utils/safestring.py +++ b/django/utils/safestring.py @@ -30,7 +30,13 @@ else: EscapeUnicode = EscapeText class SafeData(object): - pass + def __html__(self): + """ + Returns the html representation of a string. + + Allows interoperability with other template engines. + """ + return self class SafeBytes(bytes, SafeData): """ diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py index 74d94ea19d..28e9e326e0 100644 --- a/tests/utils_tests/test_html.py +++ b/tests/utils_tests/test_html.py @@ -5,7 +5,7 @@ from datetime import datetime import os from unittest import TestCase -from django.utils import html +from django.utils import html, safestring from django.utils._os import upath from django.utils.encoding import force_text @@ -192,3 +192,9 @@ class TestUtilsHtml(TestCase): self.assertEqual(quote('http://example.com/path/öäü/'), 'http://example.com/path/%C3%B6%C3%A4%C3%BC/') self.assertEqual(quote('http://example.com/%C3%B6/ä/'), 'http://example.com/%C3%B6/%C3%A4/') self.assertEqual(quote('http://example.com/?x=1&y=2'), 'http://example.com/?x=1&y=2') + + def test_conditional_escape(self): + s = '