Index: django/utils/safestring.py
===================================================================
--- django/utils/safestring.py	(revision 9781)
+++ django/utils/safestring.py	(working copy)
@@ -4,7 +4,7 @@
 that the producer of the string has already turned characters that should not
 be interpreted by the HTML engine (e.g. '<') into the appropriate entities.
 """
-from django.utils.functional import curry, Promise
+from django.utils.functional import curry, wraps, Promise
 
 class EscapeData(object):
     pass
@@ -86,13 +86,24 @@
 
     encode = curry(_proxy_method, method = unicode.encode)
 
-def mark_safe(s):
+def _safety_decorator(safety_marker, func):
+  @wraps(func)
+  def wrapped(*args, **kwargs):
+    return safety_marker(func(*args, **kwargs))
+  return wrapped
+
+
+def mark_safe(s=None):
     """
     Explicitly mark a string as safe for (HTML) output purposes. The returned
     object can be used everywhere a string or unicode object is appropriate.
 
     Can be called multiple times on a single string.
     """
+    if s is None: # Used like: @mark_safe()
+        return curry(_safety_decorator, mark_safe)
+    if callable(s): # Used like: @mark_safe
+        return _safety_decorator(mark_safe, s)
     if isinstance(s, SafeData):
         return s
     if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str):
@@ -101,7 +112,7 @@
         return SafeUnicode(s)
     return SafeString(str(s))
 
-def mark_for_escaping(s):
+def mark_for_escaping(s=None):
     """
     Explicitly mark a string as requiring HTML escaping upon output. Has no
     effect on SafeData subclasses.
@@ -109,6 +120,11 @@
     Can be called multiple times on a single string (the resulting escaping is
     only applied once).
     """
+    
+    if s is None:
+        return curry(_safety_decorator, mark_for_escaping)
+    if callable(s):
+        return _safety_decorator(mark_for_escaping, s)
     if isinstance(s, (SafeData, EscapeData)):
         return s
     if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str):
Index: tests/regressiontests/decorators/tests.py
===================================================================
--- tests/regressiontests/decorators/tests.py	(revision 9781)
+++ tests/regressiontests/decorators/tests.py	(working copy)
@@ -3,6 +3,7 @@

from django.http import HttpResponse
from django.utils.functional import allow_lazy, lazy, memoize
+from django.utils.safestring import mark_safe, mark_for_escaping
from django.views.decorators.http import require_http_methods, require_GET, require_POST
from django.views.decorators.vary import vary_on_headers, vary_on_cookie
from django.views.decorators.cache import cache_page, never_cache, cache_control
@@ -14,6 +15,7 @@
    return HttpResponse('<html><body>dummy</body></html>')
fully_decorated.anything = "Expected __dict__"

+
# django.views.decorators.http
fully_decorated = require_http_methods(["GET"])(fully_decorated)
fully_decorated = require_GET(fully_decorated)
@@ -41,8 +43,11 @@
fully_decorated = allow_lazy(fully_decorated)
fully_decorated = lazy(fully_decorated)

+# django.utils.safestring
+fully_decorated = mark_safe(fully_decorated)
+fully_decorated = mark_for_escaping(fully_decorated)
+
class DecoratorsTest(TestCase):
-
    def test_attributes(self):
        """
        Tests that django decorators set certain attributes of the wrapped
@@ -54,3 +59,37 @@
            self.assertEquals(fully_decorated.__name__, 'fully_decorated')
        self.assertEquals(fully_decorated.__doc__, 'Expected __doc__')
        self.assertEquals(fully_decorated.__dict__['anything'], 'Expected __dict__')
+
+    def test_escaping(self):
+        """
+        Tests that safety markers from django.utils.safestring
+        return the proper str or unicode subclass for use in templates.
+        
+        Tests are done by comparing directly a sample rendered Template instance
+        with the unicode content it should contain.
+        """
+        from django.template import Template, Context
+        template = Template("{{ data }}")
+
+        rendered = { 'safe': u'<html><body>dummy</body></html>', 
+          'escaped': u'&lt;html&gt;&lt;body&gt;dummy&lt;/body&gt;&lt;/html&gt;' }
+        def clean_unicode_provider():
+            return u'<html><body>dummy</body></html>'
+
+        def clean_string_provider():
+            return '<html><body>dummy</body></html>'
+
+        escaped_unicode = mark_for_escaping(clean_unicode_provider)()
+        safe_unicode = mark_safe(clean_unicode_provider)()
+        escaped_str = mark_for_escaping(clean_string_provider)()
+        safe_str = mark_safe(clean_string_provider)()
+
+        self.assertEquals(template.render(Context({'data': escaped_unicode})), 
+            rendered['escaped'])
+        self.assertEquals(template.render(Context({'data': safe_unicode})), 
+            rendered['safe'])
+        self.assertEquals(template.render(Context({'data': escaped_str})), 
+            rendered['escaped'])
+        self.assertEquals(template.render(Context({'data': safe_str})), 
+            rendered['safe'])
+
