Index: django/django/template/__init__.py
===================================================================
--- django/django/template/__init__.py	(revision 7818)
+++ django/django/template/__init__.py	(working copy)
@@ -792,7 +792,7 @@
         else:
             return force_unicode(output)
 
-def generic_tag_compiler(params, defaults, name, node_class, parser, token):
+def generic_tag_compiler(params, defaults, name, node_class, parser, token, takes_context=False, takes_nodelist=False):
     "Returns a template.Node subclass."
     bits = token.split_contents()[1:]
     bmax = len(params)
@@ -804,6 +804,12 @@
         else:
             message = "%s takes between %s and %s arguments" % (name, bmin, bmax)
         raise TemplateSyntaxError(message)
+    if takes_context:
+        node_class = curry(node_class, takes_context=takes_context) 
+    if takes_nodelist:
+        nodelist = parser.parse(('end%s' % name,)) 
+        parser.delete_first_token() 
+        node_class = curry(node_class, nodelist=nodelist) 
     return node_class(bits)
 
 class Library(object):
@@ -859,21 +865,61 @@
         self.filters[getattr(func, "_decorated_function", func).__name__] = func
         return func
 
-    def simple_tag(self,func):
-        params, xx, xxx, defaults = getargspec(func)
+    def simple_tag(self, compile_function=None, takes_context=None, takes_nodelist=None):
+        def dec(func):
+            params, xx, xxx, defaults = getargspec(func)
+            if takes_context and takes_nodelist:
+                if params[0] == 'context' and params[1] == 'nodelist':
+                    params = params[2:]
+                else:
+                    raise TemplateSyntaxError("Any tag function decorated both with takes_context=True and with takes_nodelist=True must have a first argument of 'context', and a second argument of 'nodelist'")
+            elif takes_nodelist:
+                if params[0] == 'nodelist':
+                    params = params[1:]
+                else:
+                    raise TemplateSyntaxError("Any tag function decorated with takes_nodelist=True must have a first argument of 'nodelist'")
+            elif takes_context:
+                if params[0] == 'context':
+                    params = params[1:]
+                else:
+                    raise TemplateSyntaxError("Any tag function decorated with takes_context=True must have a first argument of 'context'")
 
-        class SimpleNode(Node):
-            def __init__(self, vars_to_resolve):
-                self.vars_to_resolve = map(Variable, vars_to_resolve)
+            class SimpleNode(Node):
+                def __init__(self, vars_to_resolve, takes_context=False, nodelist=None): 
+                    self.vars_to_resolve = map(Variable, vars_to_resolve)
+                    self.takes_context = takes_context
+                    if nodelist is not None:
+                        # Only save the 'nodelist' attribute if it's not None, so that it is picked by the Node.get_nodes_by_type() method.
+                        self.nodelist = nodelist
 
-            def render(self, context):
-                resolved_vars = [var.resolve(context) for var in self.vars_to_resolve]
-                return func(*resolved_vars)
+                def render(self, context):
+                    resolved_vars = [var.resolve(context) for var in self.vars_to_resolve]
+                    if self.takes_context and hasattr(self, 'nodelist'):
+                        func_args = [context, self.nodelist] + resolved_vars
+                    elif hasattr(self, 'nodelist'):
+                        func_args = [self.nodelist] + resolved_vars
+                    elif self.takes_context:
+                        func_args = [context] + resolved_vars
+                    else:
+                        func_args = resolved_vars
+                    return func(*func_args)
 
-        compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode)
-        compile_func.__doc__ = func.__doc__
-        self.tag(getattr(func, "_decorated_function", func).__name__, compile_func)
-        return func
+            compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode, takes_nodelist=takes_nodelist, takes_context=takes_context)
+            compile_func.__doc__ = func.__doc__
+            self.tag(getattr(func, "_decorated_function", func).__name__, compile_func)
+            return func
+        
+        if takes_context is not None or takes_nodelist is not None:
+            # Examples: @register.simple_tag(takes_context=True) or @register.simple_tag(takes_context=True, takes_nodelist=True)
+            return dec
+        elif compile_function is None:
+            # @register.simple_tag()
+            return dec
+        elif callable(compile_function):
+            # @register.simple_tag
+            return dec(compile_function)
+        else:
+            raise TemplateSyntaxError("Incorrect parameters for the simple_tag decorator.")
 
     def inclusion_tag(self, file_name, context_class=Context, takes_context=False):
         def dec(func):
Index: django/tests/regressiontests/templates/tests.py
===================================================================
--- django/tests/regressiontests/templates/tests.py	(revision 7818)
+++ django/tests/regressiontests/templates/tests.py	(working copy)
@@ -17,6 +17,7 @@
 from django.utils.safestring import mark_safe
 from django.utils.tzinfo import LocalTimezone
 
+from decorators import DecoratorsTest
 from unicode import unicode_tests
 from context import context_tests
 
Index: django/tests/regressiontests/templates/decorators.py
===================================================================
--- django/tests/regressiontests/templates/decorators.py	(revision 0)
+++ django/tests/regressiontests/templates/decorators.py	(revision 0)
@@ -0,0 +1,73 @@
+from unittest import TestCase
+from unittest import TestCase
+from sys import version_info
+
+from django import template
+
+register = template.Library()
+
+# Very simple tag, with no parameters.
+def a_simple_tag_without_parameters(arg):
+    """Expected __doc__"""
+    return "Expected result"
+a_simple_tag_without_parameters.anything = "Expected __dict__"
+
+# Tag that takes the context.
+def a_simple_tag_with_context(context, arg):
+    """Expected __doc__"""
+    return "Expected result"
+a_simple_tag_with_context.anything = "Expected __dict__"
+
+# Tag that takes the inner block's node list.
+def a_simple_tag_with_nodelist(nodelist, arg):
+    """Expected __doc__"""
+    return "Expected result"
+a_simple_tag_with_nodelist.anything = "Expected __dict__"
+
+# Tag that takes both the context and the inner block's node list.
+def a_simple_tag_with_context_and_nodelist(context, nodelist, arg):
+    """Expected __doc__"""
+    return "Expected result"
+a_simple_tag_with_context_and_nodelist.anything = "Expected __dict__"
+
+# Tag that *wants* to take both the context and the inner block's node list, but that has arguments in wrong order.
+def a_simple_tag_with_context_and_nodelist_wrong_order(nodelist, context, arg):
+    """Expected __doc__"""
+    return "Expected result"
+a_simple_tag_with_context_and_nodelist_wrong_order.anything = "Expected __dict__"
+
+
+
+
+class DecoratorsTest(TestCase):
+    def verify_decorator(self, decorator, func_name):
+        # Only check __name__ on Python 2.4 or later since __name__ can't be
+        # assigned to in earlier Python versions.
+        if version_info[0] >= 2 and version_info[1] >= 4:
+            self.assertEquals(decorator.__name__, func_name)
+        self.assertEquals(decorator.__doc__, 'Expected __doc__')
+        self.assertEquals(decorator.__dict__['anything'], 'Expected __dict__')
+
+    def test_simple_tag(self):
+        # Test that the decorators preserve the decorated function's docstring, name and attributes.
+        decorator = register.simple_tag(a_simple_tag_without_parameters)
+        self.verify_decorator(decorator, 'a_simple_tag_without_parameters')
+        
+        decorator = register.simple_tag(takes_context=True)(a_simple_tag_with_context)
+        self.verify_decorator(decorator, 'a_simple_tag_with_context')
+        
+        decorator = register.simple_tag(takes_nodelist=True)(a_simple_tag_with_nodelist)
+        self.verify_decorator(decorator, 'a_simple_tag_with_nodelist')
+        
+        decorator = register.simple_tag(takes_context=True, takes_nodelist=True)(a_simple_tag_with_context_and_nodelist)
+        self.verify_decorator(decorator, 'a_simple_tag_with_context_and_nodelist')
+        
+        # Now test that 'context' and 'nodelist' arguments and their order are correct.
+        decorator = register.simple_tag(takes_context=True)
+        self.assertRaises(template.TemplateSyntaxError, decorator, a_simple_tag_without_parameters)
+        
+        decorator = register.simple_tag(takes_nodelist=True)
+        self.assertRaises(template.TemplateSyntaxError, decorator, a_simple_tag_without_parameters)
+        
+        decorator = register.simple_tag(takes_nodelist=True, takes_context=True)
+        self.assertRaises(template.TemplateSyntaxError, decorator, a_simple_tag_with_context_and_nodelist_wrong_order)
Index: django/docs/templates_python.txt
===================================================================
--- django/docs/templates_python.txt	(revision 7818)
+++ django/docs/templates_python.txt	(working copy)
@@ -1181,10 +1181,53 @@
     * If the argument was a template variable, our function is passed the
       current value of the variable, not the variable itself.
 
-When your template tag does not need access to the current context, writing a
-function to work with the input values and using the ``simple_tag`` helper is
-the easiest way to create a new tag.
+If your template tag needs to access the current context, you can use the
+``takes_context`` option as follows::
 
+    # The first argument *must* be called "context" here.
+    def current_time(context, format_string):
+        timezone = context['timezone']
+        ...
+
+    register.simple_tag(takes_context=True)(current_time)
+
+You can also use the decorator syntax if running in Python 2.4::
+
+    @register.simple_tag(takes_context=True)
+    def current_time(context, format_string):
+        ...
+
+For more information on how the ``takes_context`` option works, see the section
+on `inclusion tags`_.
+
+If your template is a simple block tag, you can use the ``takes_nodelist`` option as
+follows::
+
+    # The first argument *must* be called "nodelist".
+    def my_bock_tag(nodelist, an_argument):
+        ...
+    register.simple_tag(takes_nodelist=True)(my_bock_tag)
+
+In the above example, ``nodelist`` is a list of all nodes between 
+``{% my_bock_tag %}`` and ``{% endmy_bock_tag %}``, not counting 
+``{% my_bock_tag %}`` and ``{% endmy_bock_tag %}`` themselves.
+
+It is also possible to use both ``takes_context`` and ``takes_nodelist`` at the
+same time. For example::
+
+    # The first argument *must* be called "context" and the second one "nodelist".
+    def my_bock_tag(context, nodelist, an_argument):
+        timezone = context['timezone']
+        content = nodelist.render(context)
+        ...
+    register.simple_tag(takes_context=True, takes_nodelist=True)(my_bock_tag)
+
+If you need to create a more complex block tag, refer to the section on 
+`parsing until another block tag`_.
+
+_inclusion tags: #inclusion-tags
+_block tags: #parsing-until-another-block-tag
+
 Inclusion tags
 ~~~~~~~~~~~~~~
 
