diff --git a/django/template/base.py b/django/template/base.py
index ee33dac..96e97bb 100644
--- a/django/template/base.py
+++ b/django/template/base.py
@@ -5,6 +5,7 @@ from functools import partial
 from importlib import import_module
 from inspect import getargspec, getcallargs
 import warnings
+import copy
 
 from django.apps import apps
 from django.conf import settings
@@ -273,7 +274,7 @@ class Parser(object):
                 self.extend_nodelist(nodelist, var_node, token)
             elif token.token_type == 2:  # TOKEN_BLOCK
                 try:
-                    command = token.contents.split()[0]
+                    command = token.contents.split(None, 1)[0]
                 except IndexError:
                     self.empty_block_tag(token)
                 if command in parse_until:
@@ -288,6 +289,9 @@ class Parser(object):
                     compile_func = self.tags[command]
                 except KeyError:
                     self.invalid_block_tag(token, command, parse_until)
+                if self.has_vararg(command, token):
+                    # defer compile to the render() phase
+                    compile_func = VarArgsNode(compile_func)
                 try:
                     compiled_result = compile_func(self, token)
                 except TemplateSyntaxError as e:
@@ -379,6 +383,14 @@ class Parser(object):
         else:
             raise TemplateSyntaxError("Invalid filter: '%s'" % filter_name)
 
+    def has_vararg(self, command, token):
+        args = token.contents[len(command):]
+        if vararg_prefix in args:
+            for bit in smart_split(args):
+                if bit.startswith(vararg_prefix):
+                    return True
+        return False
+
 
 class TokenParser(object):
     """
@@ -512,9 +524,11 @@ constant_string = r"""
 }
 constant_string = constant_string.replace("\n", "")
 
+vararg_prefix = '*'
+
 filter_raw_string = r"""
 ^(?P<constant>%(constant)s)|
-^(?P<var>[%(var_chars)s]+|%(num)s)|
+^(?P<var>%(vararg_prefix)s{0,2}[%(var_chars)s]+|%(num)s)|
  (?:\s*%(filter_sep)s\s*
      (?P<filter_name>\w+)
          (?:%(arg_sep)s
@@ -529,6 +543,7 @@ filter_raw_string = r"""
     'var_chars': "\w\.",
     'filter_sep': re.escape(FILTER_SEPARATOR),
     'arg_sep': re.escape(FILTER_ARGUMENT_SEPARATOR),
+    'vararg_prefix': re.escape(vararg_prefix),
 }
 
 filter_re = re.compile(filter_raw_string, re.UNICODE | re.VERBOSE)
@@ -1067,6 +1082,72 @@ class TagHelperNode(Node):
         return resolved_args, resolved_kwargs
 
 
+class VarArgsNode(Node):
+    def __init__(self, compile_func):
+        self.compile_func = compile_func
+
+    def __call__(self, parser, token):
+        self.parser = parser
+        self.token = copy.copy(token)
+        self.contents = token.contents
+        return self
+
+    def get_filters(self, expr):
+        if expr.filters:
+            return expr.token[len(expr.var.var):]
+        return ''
+
+    def render(self, context):
+        contents = []
+        for content in smart_split(self.contents):
+            if not contents:
+                contents.append(content)
+            elif content.startswith(vararg_prefix * 2):
+                # **kwargs case
+                expr = self.parser.compile_filter(content[2:])
+                kwargs = expr.var.resolve(context)
+                if kwargs:
+                    filters = self.get_filters(expr)
+                    for name, value in kwargs.items():
+                        if isinstance(value, (int, float)) or \
+                                getattr(value, 'vararg_from_context_in_templates', False):
+                            contents.append('%s=%s%s' % (name, value, filters))
+                        elif isinstance(value, basestring):
+                            contents.append('%s="%s"%s' % (name, value, filters))
+                        else:
+                            self.bad_value_type(self.token, value)
+            elif content.startswith(vararg_prefix):
+                # *args case
+                expr = self.parser.compile_filter(content[1:])
+                args = expr.var.resolve(context)
+                if args:
+                    filters = self.get_filters(expr)
+                    for value in args:
+                        if isinstance(value, (int, float)) or \
+                                getattr(value, 'vararg_from_context_in_templates', False):
+                            contents.append('%s%s' % (value, filters))
+                        elif isinstance(value, basestring):
+                            contents.append('"%s"%s' % (value, filters))
+                        else:
+                            self.bad_value_type(self.token, value)
+            else:
+                contents.append(content)
+
+        contents = ' '.join(contents)
+        if not (self.token.contents == contents and hasattr(self, 'nodelist')):
+            # recompile
+            self.token.contents = contents
+            parser = self.parser.__class__([self.token])
+            parser.tags = self.parser.tags
+            self.nodelist = parser.parse()
+        return self.nodelist.render(context)
+
+    def bad_value_type(self, token, value):
+        raise TemplateSyntaxError(
+            "Only string/numeric types can be unpacked from "
+            "templatetag variable argument list: '%s'" % value)
+
+
 class Library(object):
     def __init__(self):
         self.filters = {}
diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py
index ed3a019..8e83288 100644
--- a/tests/template_tests/tests.py
+++ b/tests/template_tests/tests.py
@@ -1956,3 +1956,70 @@ class SSITests(TestCase):
         with override_settings(ALLOWED_INCLUDE_ROOTS=(self.ssi_dir,)):
             for path in disallowed_paths:
                 self.assertEqual(self.render_ssi(path), '')
+
+
+class VarAragsTests(TestCase):
+    def test_varargs(self):
+        c = template.Context({'args': [1], 'kwargs': {'a': 3, 'b': 4}})
+        t = template.Template('{% load custom %}{% assignment_unlimited_args_kwargs *args **kwargs 5=5 as var %}The result is: {{ var }}')
+        self.assertEqual(t.render(c), 'The result is: assignment_unlimited_args_kwargs - Expected result: 1, hi / 5=5, a=3, b=4')
+
+    def test_varargs_no_params(self):
+        c = template.Context({'args': [], 'kwargs': {}})
+        t = template.Template('{% load custom %}{% no_params *args **kwargs %}')
+        self.assertEqual(t.render(c), 'no_params - Expected result')
+
+        six.assertRaisesRegex(self, template.TemplateSyntaxError,
+            "'no_params' received too many positional arguments",
+            template.Template, '{% load custom %}{% no_params "*args" %}')
+
+    def test_varargs_filter(self):
+        c = template.Context({'args': ['3', 4], 'kwargs': {'a': '1', 'b': 2}})
+        t = template.Template('{% load custom %}{% assignment_unlimited_args_kwargs 1 *args|add:20|add:10 **kwargs|add:"10" 3=3 as var %}{{ var }}')
+        self.assertEqual(t.render(c), 'assignment_unlimited_args_kwargs - Expected result: 1, 33, 34 / 3=3, a=11, b=12')
+
+    def test_varargs_include(self):
+        c = template.Context({'args': ['inclusion.html'], 'kwargs': None, 'result': 'OK'})
+        t = template.Template('{% include *args **kwargs %}')
+        self.assertEqual(t.render(c), 'OK\n')
+
+    def test_varargs_cycle(self):
+        c = template.Context({'ll': [('1', '2', '3',), ('4', '5', '6',), ('a', 'b', 'c')]})
+        t = template.Template('{% for l in ll %}{% for i in l %}i:{{ i|safe }}, c:{% cycle *l %}; {% endfor %}{% endfor %}')
+        self.assertEqual(t.render(c), 'i:1, c:1; i:2, c:2; i:3, c:3; i:4, c:4; i:5, c:5; i:6, c:6; i:a, c:a; i:b, c:b; i:c, c:c; ')
+
+    def test_varargs_bad_type(self):
+        c = template.Context({'kwargs': {'': lambda: None}})
+        t = template.Template('{% load custom %}{% assignment_unlimited_args_kwargs **kwargs as var %}')
+        six.assertRaisesRegex(self, template.TemplateSyntaxError,
+            "Only string/numeric types can be unpacked from templatetag variable argument list:",
+            t.render, c)
+
+    def test_varargs_missing_context(self):
+        # The 'context' parameter must be present when takes_context is True
+        # exception will be raised in t.render() phase
+        c = template.Context({'args': [123]})
+        t = template.Template('{% load custom %}{% assignment_tag_without_context_parameter *args as var %}')
+        six.assertRaisesRegex(self, template.TemplateSyntaxError,
+            "'assignment_tag_without_context_parameter' is decorated with takes_context=True so it must have a first argument of 'context'",
+            t.render, c)
+
+    def test_vararg_from_context(self):
+        class MyStr(str):
+            vararg_from_context_in_templates = True
+ 
+        my_str = MyStr('*objs')
+        c = template.Context({'objs': [1, 2], 'args': [my_str]})
+        t = template.Template('{% load testtags %}{% echo *args %}')
+        self.assertEqual(t.render(c), '1 2')
+
+        my_str.vararg_from_context_in_templates = False
+        self.assertEqual(t.render(c), '"*objs"')
+
+    def test_varargs_from_context_dot(self):
+        class MyStr(str):
+            vararg_from_context_in_templates = True
+
+        c = template.Context({'args': [MyStr('data.0')], 'kwargs': {'a': MyStr('data.1')}, 'data': ['abc', 'def']})
+        t = template.Template('{% load custom %}{% assignment_unlimited_args_kwargs 1 *args **kwargs 3=3 as var %}{{ var }}')
+        self.assertEqual(t.render(c), 'assignment_unlimited_args_kwargs - Expected result: 1, abc / 3=3, a=def')
